这章主要讲编译时类型和运行时类型,简单来说,Student stu=new Student(); 等号左边stu是编译时类型,等号右边new Student()是运行时类型,stu存在在栈内存中,new Student()在堆内存中。
当编译时的类型和运行时的类型不一样时,就会出现多态。
对象的多态性
例如:
Person p=new Student();
Person e=new Student();
Person p=new Pernson();
p = new Student();
/**
*问题:当前这个引用对象引用的是哪个实例对象?
*答:刚开始p指向了new Person,后来p指向了new Student。所以他目前指向了Student
*/
这就是我们说的向上转型。
属性是在编译时确定的。
一个引用类型变量如果声名为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性方法。
父类Person
public class Person {
int age;
String name;
int sex;
public void showInfo(){
System.out.println("这是父类");
System.out.println(this.age);
System.out.println(this.name);
System.out.println(this.sex);
}
}
子类Student
public class Student extends Person{
String school;
public void showInfo(){
System.out.println("这是子类");
System.out.println(this.name);
System.out.println(this.age);
System.out.println(this.sex);
System.out.println(this.school);
}
}
public class test {
public static void main(String[] args) {
Student s=new Student();
Person e=new Student();
s.school="tiantain";
e.school="tiantian";//此方法错误,引用类型变量如果声名为父类的类型,则该变量就不能再访问子类中添加的属性方法。
//属性是由编译期决定的,编译时e为Person类型,没有school成员变量,所以会编译出错。
}
}
方法的多态性:
拿上面例子来说,当:
e.showInfo();
那么此时e会调用父类还是子类的showInfo呢?答案是他调用的是student的类的showInfo
编译时e为Person类型,而方法的调用是在运行时确定的,所以他调用的是student的方法。
如果子类没有重写父类的方法,那么子类就是直接使用父类的方法。
如果重写了,子类就使用自己重写之后的。