一、多态
- 【前提:】
-
- 一定要有继承、实现关系
-
- 要有方法重写
-
- 父类引用指向子类对象 【父类 = new 子类】
-
举个栗子
class Person {}
class Student extends Person {}
class Demo {
@Test
public void Test(){
//父类引用 子类对象
Person p = new Student();
}
}
- 成员访问特点
- 除了成员 <方法> 以外,编译看左边 [父类],运行看右边 [子类](因为子类可能重写了父类方法)
- 其余所有成员,都是编译看左边 [父类],运行看左边 [父类]
举个栗子
class Person {
String name;
public void method(){
System.out.println("Person method running...");
}
}
class Student extends Person {
int age;
public void method(){
System.out.println("Student method running...");
}
public void method02(){
System.out.println("Student method02 running...");
}
}
class Demo {
@Test
public void Test(){
Student stu = new Student();
stu.name = "stu";
stu.age = 18;
stu.method(); //输出: Student method running...
stu.method02(); //输出: Student method02 running...
System.out.println(stu.name); //输出: stu
System.out.println(stu.age); //输出: 18
//多态
Person p = new Student();
p.name = "per";
//非成员方法的成员【编译看左边(父类:Person),运行看左边(父类:Person)】
//p.age = 66; //报错,父类方法 Person 中没有定义 age 变量,无法通过编译
p.method(); //输出:Student method running...
//成员方法 编译看左边(父类:Person),运行看右边(子类:Student)
//p.method02(); // 报错,因为父类方法 Person 中没有定义 method02() 方法无法通过编译
}
}
- 静态绑定
- 类被加载时,类中的某些成员,都已经同该类绑定在一起了,所以不论如何调用,调用的都是该类的成员。
- 构造方法、private、static、final方法或者变量,都属于静态绑定。
- 动态绑定
- 类中的成员方法属于动态绑定,只有在程序运行的那一刻,才知晓,该方法,有没有被子类重写(覆盖)。
- 好处
- 提高了代码可扩展性。
- 方法的参数如果是一个父类,则可以传入该父类的所有子类进入方法。
- 弊端
- 不能调用子类的特有成员。(因为编译都是看左边。)
- 如果想要调用子类的特有成员,需要向下转型(强转)。
- 可能出现的问题:ClassCastException 类型转换异常。
关键字: [instanceof] 判断左边的对象,是否是右边的类型,或者其子类型。
格式: 对象 instanceof 类型
- 可能出现的问题:ClassCastException 类型转换异常。
举个栗子
class Animal{}
class Cat extends Animal {}
class Dog extends Animal {}
class Demo {
@Test
public void Test() {
Animal a = new Cat();
Cat c = (Cat)a; // 可以的! 因为本类a 创建出来的就是一只猫,所以可以强行将其a转回猫。
//Dog d = (Dog)a; // 报错。因为a是一只猫,不能强行将其转成狗。
//关键字 instanceof 的使用
Dog dog = new Dog();
if(dog instanceof Cat){ //判断 dog 对象是否为 Cat 类型,如果是则返回 【true】, 否则返回 【false】
Cat cat = (Cat) dog;
}
}
}
- 类型转换
- 基本类型:
- 隐式类型转换: 小 -> 大
- int a = 10;
- double d = a;
- 强制类型转换: 大 -> 小
- double d = 3.14;
- int a = (int)d; // a = 3; 丢失精度
- 隐式类型转换: 小 -> 大
- 引用类型:
- 向上转型: 子 -> 父
- Cat c = new Cat();
- Animal a = c;
- 向下转型: 父 -> 子
- Animal a = new Cat();
- if(c instanceof Cat){
Cat c = (Cat)a;c.watchMouse(); // 调用子类的特有方法。
}
- 向上转型: 子 -> 父
- 基本类型:
二、抽象类
关键字: [abstract]
格式: 权限修饰符 abstract 类型 标识符
唯一的作用:当父类使用
-
提供资源给子类使用,子类必须重写父类的所有抽象方法。
-
特点
- 不能创建对象(不能被new)
- 有抽象方法,要求子类必须重写。
除非子类也是抽象类。
抽象类的成员,同普通父类除了不能创建对象和有抽象方法以外,没有任何区别!!!!
抽象类有构造方法
-
给成员变量赋值。
-
子类的构造方法中,通过super()可以调用抽象类的构造方法,给成员变量赋值。
-
abstract不能同以下关键字共存:
- final: final修饰的方法,子类不能重写,而抽象方法要求子类必须重写。相矛盾。
- static:static修饰的方法,可以被类名直接调用,而抽象方法没有方法体,调用毫无意义。
- private: private修饰的方法,子类根本就不知道有这么一个方法,如果无法重写。
三、接口
关键字: [interface]
格式: 权限修饰符 interface 标识符
- 作用
- 制定规则
- 扩展功能
- 接口成员变量
- 静态常量(在接口中定义的变量都会自动加上【final】关键字,使其成为静态常量)
- 抽象方法(给子类指定规则,子类需实现抽象类中的所有抽象方法)
jdk 8之后,多了静态方法,默认方法。
- 解决接口升级的问题
public default void method(){} // 默认方法 - 让接口拥有一些自己的方法
public static void show(){} // 静态方法
== JDK 9之后,多个私有方法。== - 抽取接口中多个静态方法、默认方法中的共性内容,供静态方法和默认方法使用
private void fun(){}
接口与类的关系
-
类与类
- 单继承、多层继承。
- 单继承、多层继承。
-
类与接口
- 多实现,多层实现。
- 多实现,多层实现。
- 接口与接口
- 多继承、多层继承。
- 多继承、多层继承。