1.java引用变量
之前谈过,在方法中并未真正“拥有”一个变量,而是在栈区中进行对堆区变量的引用,在java中,引用变量有两个类型,一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定,而运行时由实际赋给变量的对象决定。如果编译时类型和运行时不一致,就会出现多态(Polymorphism)
Bird bird=new Bird();
/**
Bird bird:编译时赋给该变量类型Bird
new Bird:运行时赋给该变量Bird
*/
2.举个栗子
public class Bird {
public void fly(){
System.out.println("i am flying in the sky");
}
}
public class Ostrich extends Bird {
public void fly(){
System.out.println("i am only running in the land");
}
public void callOverridedMethod(){
super.fly();
}
public static void main(String[]args){
//多态 访问Ostrich的方法
Bird bird=new Ostrich();
Bird bird1=new Bird();
bird.fly();
bird1.fly();
}
}
3.说明
*对于上述代码而言 bird1的编译时类型为Bird 运行时类型也为Bird,但是对于bird而言 ,编译时类型为Bird,运行时类型为Ostrich,所以产生了多态现象,调用了子类(Ostrich)的fly方法。
*因为子类是一种特殊的父类,因此,java允许把一个子类对象直接赋给一个父类引用变量,无需进行任何类型转换(向上转型),由系统自动完成
*当把子类变量赋给父类引用变量时,被称为向上转型(upcasting),这种转型只是说明引用变量的编译类型是父类,但是实际执行的方法,依然表现出子类对象的行为方式,但是如果把父类对象如果赋给子类对象,需要强制转换,而且可能在运行时产生异常(ClassCastException)
4.如何安全的进行类型转换?
instanceof 运算符的前一个操作数通常是一个引用类型变量,后一个通常为操作类(或接口),它用来判断前面的对象是否是后面类的子类,实现类的实例 如果是 返回true 不是 返回 false
public class Ostrich extends Bird {
/**
* 方法重写:函数名一致 内部处理逻辑不通
*/
public void fly(){
System.out.println("i am only running in the land");
}
public void callOverridedMethod(){
super.fly();
}
public static void main(String[]args){
//多态 访问Ostrich的方法
Bird bird=new Ostrich();
Bird bird1=new Bird();
System.out.println(bird instanceof Bird); //true
System.out.println(bird1 instanceof Ostrich);//false
}
}
所以 如果使用强制转换之前,一般先判断一个对象是否可以强制类型转换,这样的话,可以使得代码更加健壮