继承
继承使用关键词extends,继承格式为class Son extends Father{}。
Java不支持多继承(一个类同时继承自好几个类),支持多重继承、不同类继承同一个类。
特性
- 子类会继承父类的非private的属性和方法;
- 子类可以添加自己新的属性和方法;
子类可以重写/实现父类的方法/抽象方法;
继承关键字
extends关键字: 继承自某一个父类;
implements关键字: 继承接口;
super和this: super用于实现对父类成员的访问,比如在实现子类的构造方法时可以直接调用super(可有参数)来完成父类的构造;this是自己的引用,常用于方法或者构造方法里,若方法里的传参有和类中相同名字的参数,使用this.name = name可以实现调用,如果没有相同的参数,直接使用名字就能完成操作,不需要this;重写与重载
重写
重写(Override)的定义是子类中写了一个其父类中具有相同名称、参数列表和返回类型(可以不同)的方法。
规则如下:- 参数列表与被重写方法的参数列表必须完全相同;
- 返回参数类型可以不同;
- 访问权限不能比父类中被重写的方法的访问权限更低;
声明为final的方法不能被重写;声明为static的方法不能被重写,但能再次被声明。
如果在进行重写时需要调用父类的被重写方法,需要使用super关键字,比如:class Jiangjun{ public void speak(){ System.out.println("Zhongcheng!"); } } class JinZhengEn extends Jiangjun{ public void speak(){ super.speak(); system.out.println("写代码要用手"); } }
重载
或者可以叫做重构,指的是在一个类里面,方法名字相同,参数必须不同的方法。返回类型可以相同。不同的重载方法可以独立存在。
重载类型的参数列表必须不同,且一定可以区分,比如取不同的参数变量名、字符串等容易混淆的方式是不合法的。
异常和访问权限都可以任意修改。
| 区别点 | 重载方法 | 重写方法 |
|---|---|---|
| 参数列表 | 必须修改 | 一定不能修改 |
| 返回类型 | 可以修改 | 一定不能修改 |
| 异常 | 可以修改 | 可以减少或删除,一定不能抛出新的或者更广的异常 |
| 访问 | 可以修改 | 一定不能做更严格的限制(可以降低限制) |
多态
多态指的是对于同一个接口(方法),使用不同的实例(子类)会执行不同的操作。
多态存在的三个必要条件:
- 继承
- 重写
父类引用指向子类的对象:
Parent p = new Child();
Example(From菜鸟教程):public class Test { public static void main(String[] args) { show(new Cat()); // 以 Cat 对象调用 show 方法 show(new Dog()); // 以 Dog 对象调用 show 方法 Animal a = new Cat(); // 向上转型 a.eat(); // 调用的是 Cat 的 eat Cat c = (Cat)a; // 向下转型 c.work(); // 调用的是 Cat 的 work } public static void show(Animal a) { a.eat(); // 类型判断 if (a instanceof Cat) { // 猫做的事情 Cat c = (Cat)a; c.work(); } else if (a instanceof Dog) { // 狗做的事情 Dog c = (Dog)a; c.work(); } } } abstract class Animal { abstract void eat(); } class Cat extends Animal { public void eat() { System.out.println("吃鱼"); } public void work() { System.out.println("抓老鼠"); } } class Dog extends Animal { public void eat() { System.out.println("吃骨头"); } public void work() { System.out.println("看家"); } }虚函数
虚函数指的是在父类中声明的方法,可以在子类中被重写,并且在运行时根据对象的实际类型调用对应的版本,而不是编译时根据引用类型调用。
Java里面没有虚函数的概念,普通函数就相当于虚函数,加上final关键字变成非虚函数。
不同的引用如何理解:
对于一个父类Animal和子类Dog,不管是Animal alh = new Dog();还是Dog alh = new Dog();,两者实际上实例化的都是Dog对象(只有new才会创建新的空间,前面的“=”只是引用),只是一个用Dog引用,另外一个用Animal引用,最后调用对象和方法的时候都会使用真实的类,也就是Dog。
这里同时涉及到了编译时类型和运行时类型的区别。alh编译时的类型是Animal,变量实际运行时指向的是对象类型,指向的类型是Dog。编译的时候,编译器只根据变量的编译时类型检查方法是否存在。如果Dog里面重写Animal里面的方法,不会报错,且使用的是Dog中的重写方法;而如果Dog里面有方法,Animal里面没有,编译时编译器会检查发现Animal里面没有对应方法,编译器报错。
抽象
抽象类
抽象类是一种不能实例化对象的类,类的其他功能依旧存在。在Java里面使用abstract class来定义抽象类。
抽象类不能用来实例化对象,所以抽象类必须要被继承才能被使用。父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。继承的时候可以通过super()构造父抽象方法,同样可以调用和获取三个变量。
抽象方法
抽象方法同样使用abstract关键字定义,在定义它的类里面不实现它,这个方法的具体是先由它的子类确定。在父类里面只包含一个方法名,没有方法体,方法名后面直接跟一个分号就行。如:
public abstract class People{
public abstract double study();
}有抽象方法的类必须满足:
- (1)如果一个类包含抽象方法,那么该类必须是抽象类;
- (2)任何子类必须重写父类的抽象方法,或者声明自身为抽象类。
封装
封装的意思是指把类里面的部分方法的实现细节(如内部的变量)部分包装、隐藏起来,防止类的代码和数据被外部类定义的代码访问,要访问内部的代码和数据必须通过严格的接口控制。
封装的实现首先需要对于变量添加可见性,限制对于类的属性的访问,一般使用private进行限制。比如把变量设置为私有的,只有本类能进行访问,然后添加公共方法提供访问和赋值方法,这两种方法称为getter和setter方法。
接口
接口是Java里面的一个抽象类型,是抽象方法的集合,使用interface来声明。
定义类的时候可以通过继承接口,来继承接口的抽象方法。接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。
接口有以下的特性:
- 借口中的每一个方法会被隐式的指定为public abstract类型(只可以指定为这一个类型)
- 接口可以含有变量,只能有static final变量;
- 接口内部不能实现方法,只是把方法的声明写好(相比抽象类,抽象类里面的方法可以有实现方法的具体实现);
一个类可以实现多个接口。
接口的声明语法结构如下:interface 接口名称 [extends 其他的接口名]{ // 声明变量 // 抽象方法 }接口的实现
当类实现接口时,非抽象类需要实现接口里面所有的方法。使用implements关键字来实现接口。比如:
public class Panda implements Animal{ public void eat(){ sout("..."); } public int test(){ return 0; } }
接口的继承
一个接口能继承另一个接口,和类之间的继承方式比较相似。接口的继承使用extends关键字,子接口继承父接口的方法。
接口中支持多继承,比如public interface ALH extends Animal, People。
标记接口: 最常用的标记接口是没有包含任何方法的接口。标记接口是没有任何方法和属性的接口.它仅仅表明它的类属于一个特定的类型,供其他代码来测试允许做一些事情。
标记接口作用:简单形象的说就是给某个对象打个标(盖个戳),使对象拥有某个或某些特权。