编译时多态
- 设计时多态方法重载
运行时多态
- 程序运行时动态决定调用那个方法
必要条件
- 满足继承关系
- 父类引用指向子类对象
向上转型
- 父类引用指向子类实例,可以调用子类重写父类的方法以及父类派生的方法,无法调用子类独有的方法
- 父类中的静态方法无法被子类重写,所以向上转型之后,只能调用到父类原有的静态方法
向下转型
- 子类引用指向父类对象,此处可以使用
instanceof
进行检查,避免类型转换时的安全性问题 - 可以调用子类独有的方法
抽象类 abstract class
- 限制实例化
- 只能被继承
- 应用场景: 某个父类只是知道其子类应该包含怎样的方法,但无法准确知道这些子类如何实现这些方法
抽象方法 abstract method
- 不能有方法体
- 必须由子类实现
- 子类如果没有重写父类的所有抽象方法,则也要定义为抽象类
接口 Interface
- 当多个类具有相同能力的时候,可以使用接口抽象出相同的能力
- 接口定义了某一批类所需要遵守的规范
- 接口不关心这些类的内部数据,也不关心这些类里的方法的实现细节,它只规定这些类里必须提供某些方法
- 接口方法可以不写
abstract
关键字,并且默认为public的访问权限 - 当类实现接口时,需要去实现接口中的所有抽象方法,否则需要将该类设置为抽象类
- 接口中可以定义常量,默认为
public static final
默认方法
- 自JDK1.8之后,接口中可以存在默认方法,使用
default
关键字定义 - 默认方法可以带方法体,子类实现接口时可以不用实现默认方法
- 子类可以重写默认方法,并可以通过接口的引用调用
静态方法
- 自JDK1.8之后,接口中可以存在静态方法,使用
static
关键字定义 - 静态方法可以带方法体,子类可以通过使用接口名访问接口的静态方法
多重实现
- 子类可以继承一个父类,但是可以实现多个接口
- 当多个接口中具有相同签名的方法时,子类需要重写方法
- 当父类和接口具有相同签名的方法时,父类方法具有优先权
- 当父类和接口具有相同名字的变量时,子类需要重新定义该变量,父类中的变量不具有优先权
接口的继承
- 接口也可以实现继承关系
- 接口可以继承多个父接口
1 | public interface ParentOne { |
内部类
- 内部类提供了更好的封装,不允许其他外部类访问内部类的信息
成员内部类
- 最常见的内部类,也称为普通内部类
- 内部类在外部使用时,无法直接实例化,需要借由外部类信息才能完成实例化
- 内部类的访问修饰符,可以是任意的,但是访问权限会受到修饰符的影响
- 内部类可以直接访问外部类的成员(包括成员属性和成员方法),如果出现同名属性,优先访问内部类中定义的
- 外部类访问内部类的信息需要通过内部类的实例,无法直接访问
- 内部类编译后得class文件名:外部类$内部类.class
获取内部类对象实例
- new 外部类.new 内部类
1 | Person.Heart myHeart = new Person().new Heart(); |
- 外部类对象.new 内部类
1 | myHeart = myPerson.new Heart(); |
- 外部类对象.获取方法
1 | myHeart = myPerson.getHeart(); |
静态内部类
- 静态内部类中,只能直接访问外部类的静态成员
- 需要使用外部类的实例对象来访问非静态成员
- 访问静态内部类对象实例时,可以不依赖于外部类对象
获取静态内部类实例
1 | Person.Heart myHeart = new Person.Heart(); |
方法内部类
- 定义在外部类方法中的内部类,也成为局部内部类
- 方法内部类中无法定义静态成员
- 类中可以使用final,abstract成员
- 和方法内部成员使用规则一样,class前面不可以添加public,private,protected,static等关键字
匿名内部类
- 将类的定义和类的创建放在一起完成,程序只会用到一次类的实例,所以类名无关紧要
- 对于抽象类Person来说,如果我们想调用其中的抽象方法,一种做法是创建一个实现read方法的子类
- 但是如果这个子类只会被用到一次,那这个子类的名字就不重要,就可以使用匿名内部类来解决
- 无法使用private,public,protected,static修饰
- 无法编写构造方法,但是可以添加初始化代码块
- 不能出现静态成员
- 可以实现接口也可以继承父类,但是不能同时
1 | public abstract class Person { |
匿名类的例子
-
在我们使用comparator对Collections进行排序的时候可以使用匿名类来省去创建子类的过程
-
不使用匿名类对List排序
1 | // create a child class implements parent Comparator |
- 使用匿名类对list排序
1 | public class testComparator() { |
- 自Java1.8以后,可以使用lambda expression来省去方法名,匿名方法
1 | public class testComparator() { |
- 因为上面的匿名方法和String里面定义的compareTo方法一样,我们可以使用method reference来更加简化代码
1 | public class testComparator() { |