多态
方法重载 和 方法重写 都体现出了多态。
编译类型:是在编译时由声明该变量时使用的类型决定的,已经在编译时确定好了,有多少的内存空间,这是无法改变的。
运行类型:由实际赋值给该变量的对象决定,是可以重新赋值内存空间来修改的。
Pig的构造方法,先调用父类的构造方法,先将父类的成员进行初始化,然后再对子类进行初始化。
Animal是父类,但是我们可以传子类进去,因为父类的内存位置是与子类一样的,我们仍可以找到这块空间。
引用对象animal可以调用父类中的所有成员(遵守访问权限),但是不能调用子类的特有成员。
这是因为animal的编译类型是Animal,我们只知道Animal的内存位置,并不知道Cat的内存位置。
在编译阶段,能调用哪些成员,是由编译类型来决定的。
当有方法重写时,优先调用子类的方法,这与前面的方法调用规则一致。
这是因为方法重写将原先的那块空间给重新赋值了,所以父类能够访问到子类的方法。
Cat cat = (Cat)animal;
cat.catchMouse();
将animal的编译类型Animal强制类型转换成Cat类型。
父类的引用必须指向的是要强制类型转换的对象。
e.g.父类为Animal animal(父类的引用) = new Cat();
Cat cat = (Cat)animal; // OK
Dog dog = (Dog)animal; // err
instanceof(比较操作符)
in-内 + st-站 + ance表n. -> 站在里面的东西(例子)
作用:判断一个对象是否为一个类的实例。
AA aa = new BB(); // 向上转型
aa的编译类型为AA父类,运行类型为BB子类
这边看的是运行类型,所以都是true。
这里是一个父类的对象引用 是否为 一个子类的实例,这就错了。
动态绑定机制
System.out.println(a.sum());
a的运行类型是B,所以JVM会先去看B类中有没有sum()
这时在B类中没有sum()方法,继承机制发动,他会在父类中找有没有sum()方法,如果没有报错。
在父类中有,里面又有一个getI()
方法,动态绑定机制发动(动态绑定会自动将父类的方法绑定到子类上),
发现有getI()
这个方法,return的 i 为就是子类的i
多态数组
main
package com.Test.pkg;
public class main {
public static void main(String[] args) {
// 创建1个Person对象,2个Stu..对象,2个Tea..对象,放在数组中
Person[] persons = new Person[5];
persons[0] = new Person("jack", 20);
persons[1] = new Student("jack", 18, 100);
persons[2] = new Student("smith", 19, 30.1);
persons[3] = new Teacher("scott", 30, 20000);
persons[4] = new Teacher("king", 50, 25000);
for (int i = 0; i < persons.length; ++i) {
// 它会先去运行机制里找有没有say()这个方法,
// 这个就是动态绑定机制了~
System.out.println(persons[i].say());
// 判断persons[i]的运行类型是不是Student
if (persons[i] instanceof Student) {
((Student)persons[i]).study();
} else if (persons[i] instanceof Teacher) {
((Teacher)persons[i]).teach();
}
}
}
}
Person
package com.Test.pkg;
public class Person {
// 1.成员属性
private String name;
private int age;
// 2.构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 3.属性的get和set方法
// 顺口溜
// get:要得值,必返回(只要是方法都得有返回值,构造器除外)
// set:要改值,必传值
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String say() {
return "name = " + name + "\t" + " age = " + age;
}
}
Student
package com.Test.pkg;
public class Student extends Person {
// 因为这里子类继承了父类,所以先要调用父类Person的构造器
// 父类Person的默认构造器被覆盖了,所以我们要用super来调用
private double score;
// 子类的构造器
public Student(String name, int age, double score) {
super(name, age);
this.score = score;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
// 子类方法重写say方法
public String say() {
return super.say() + " score = " + score;
}
public void study() {
System.out.println("学生:" + getName() + "正在学Java");
}
}
Teacher
package com.Test.pkg;
public class Teacher extends Person {
private double salary;
public Teacher(String name, int age, double salary) {
super(name, age);
this.salary = salary;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
// 重写父类的say()方法
public String say() {
return super.say() + " salary = " + salary;
}
public void teach() {
System.out.println("老师:" + getName() + "正在讲Java课程");
}
}