向下转型:把引用变量转化为子类类型
向上转型:把引用变量转化为父类类型
- Base.java
public class Base {
//父类实例变量
String var = "baseVar";
//父类的静态变量
static String staticVar = "staticBaseVar";
//父类实例方法
void method(){
System.out.println("Base method");
}
//父类静态方法
static void staticMethod(){
System.out.println("static Base method");
}
}
- Sub.java
public class Sub extends Base{
String var = "subVar";
static String staticVar = "staticSubVar";
void method(){
System.out.println("sub static method");
}
String subVar = "var only belonging to Sub";
static void subMethod(){
System.out.println("method only belonging to sub");
}
public static void main(String[] args){
Base who = new Sub();
System.out.println("who.var=" + who.var);
System.out.println("who.staticVar=" + who.staticVar);
who.method();
who.staticMethod();
Sub sub = (Sub) who;
sub.subVar = "23";
sub.subMethod();
Base base2 = new Base();
Sub sub2 = (Sub) base2;
sub2.subMethod();
}
}
====运行输出=====
who.var=baseVar
who.staticVar=staticBaseVar
sub static method
static Base method
method only belonging to sub
Exception in thread "main" java.lang.ClassCastException: sc.demo1.Base cannot be cast to sc.demo1.Sub
at sc.demo1.Sub.main(Sub.java:25)
- 详细解释
-
Base who = new Sub();
who 被声明为Base类型,引用Sub实例 -
who.method();
基于java动态机制,who的类型是Base,但实际引用的是Sub类,new Sub()会在堆区分配内存空间
当who.method()方法时,jvm会根据who持有的引用定位到堆区的Sub实例
再根据Sub持有的引用 定位到方法区Sub类的类型信息 获得method的字节
在当前环境下(上面代码所示)获得method的字节码,此时Sub类复写了Base的method的方法,
获得method的字节码,直接执行method包含的指令,
如果没有复写method方法 则去获得Base类的字节码 执行包含的指令
- Base类型,who.subVar="123";
编译错误,Base没有subVar属性
对于一个引用变量,java编译器按照它什么的类型来处理
-
Sub sub = (Sub) who;
如果要访问Sub类成员,可以进行强制类型转换(向下转型) -
sub2.subMethod();
编译通过 但是抛出ClassCastException
sub2实际引用的是Base实例
对应一个引用类型的变量,运行时jvm按照它实际引用的对象来处理,假设上面能够通过,但是
当我们sub2引用变量调用subMethod()方法时,我们看到在Base类中并没有subMethod方法。
由此可见 ,子类对象可以向上转型为父类对象,但是父类对象不能转换为子类对象,父类拥有的成员子类
子类肯定也有,而子类拥有的成员父类不一定有 -
总结
在运行时环境中,通过引用类型变量来访问所引用的方法和属性时,java虚拟机采用如下绑定机制。
实例方法与引用变量 实际引用的对象 的方法绑定 属于动态绑定.由运行时jvm动态决定的。
静态方法与引用变了所声明的对象 的方法绑定 属于静态绑定 在编译阶段就已经做了绑定
成员变量 (静态和实例)与引用变量所声明的类型的成员变量绑定属于静态绑定。
网友评论