public class Base {
public final String FOO = "foo"; public String getFOO() {
return FOO;
} public static void main(String[] args) {
Base b = new Base();
Sub s = new Sub(); System.out.print(b.FOO);
System.out.print(s.FOO);
System.out.print(((Base) s).FOO); System.out.println(); System.out.print(b.getFOO());
System.out.print(s.getFOO());
System.out.print(((Base) s).getFOO());
}
}class Sub extends Base {
public final String FOO = "bar"; @Override
public String getFOO() {
// TODO Auto-generated method stub
return FOO;
}
}
// print --> :
// foobarfoo
// foobarfoo強制轉換后
爲什麽調用變量和調用方法效果不一樣?

解决方案 »

  1.   

    // print --> :
    // foobarfoo
    // foobarfoo
    你自己说结果是这样了,那里不一样啊?
    还有,不能打简体吗?
      

  2.   


    我寫錯了,不好意思
    foobarfoo
    foobarbar在公司,由於某種原因採用繁體的
      

  3.   

    1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制.
    2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。)
    3. 堆:存放所有new出来的对象。
    4. 静态域:存放静态成员(static定义的)
    5. 常量池:存放字符串常量和基本类型常量(public static final)。
    6. 非RAM存储:硬盘等永久存储空间对象的引用和对象的函数各自存放在属于这个对象的栈中,而他的FOO存放在属于他的那片常量池看完这个应该就明白了吧!
      

  4.   

    这与调用的是变量还是方法是无关的。
    这句System.out.print(((Base) s).getFOO());之所以输入bar,是因为@Override 。
      

  5.   

    补充说明一下 final 修饰的变量是不可继承的,所以当强转类型后,直接访问变量是foo,而访问的可继承的方法,输出则是bar。
      

  6.   

    解决这个问题的主要问题是final这个修饰词的特点:final修饰的变量和方法和类是不能被继承的;FOO是被final修饰的所以是没被继承的;但是getFOO()就不一样了,他是被继承了;所以强制转换后输出的结果当然不一样了。
    输出结果是:
    foobarfoo
    foobarbar
      

  7.   

    类似问题有人问过了
    属性是静态绑定,即编译时,属性就被编译成一个相对地址,对属性的操作就是对该相对地址的操作
    而方法是动态绑定,也就是编译时,为方法生成一个虚拟表(可以想象成一个Map,Key是方法名,Value是方法的地址),方法调用,通过虚拟表找到方法的地址进行调用

    System.out.print(b.FOO); //这里相当于被编译为print(Base实例的Foo地址)
    System.out.print(s.FOO); //这里是print(Sub实例的Foo地址)
    System.out.print(((Base) s).FOO); //这里是print(Base实例的Foo地址)System.out.print(b.getFOO()); //这里相当于被编译为print(方法名getFoo),
                                 //同时为Base实例生成一个虚拟表
                                 //表的内容是->方法名(getFoo),方法地址(Base的getFoo方法的地址) 
    System.out.print(s.getFOO()); //这里是print(方法名getFoo),
                                 //同时为Sub实例生成一个虚拟表
                                 //表的内容是->方法名(getFoo),方法地址(Sub的getFoo方法的地址)
    System.out.print(((Base) s).getFOO());//这里是print(方法名getFoo)
    //这样,因为s指向的时Sub实例,所以调用方法的时候,到Sub的虚拟表里去查找方法的地址,所以不管怎样强行转换为父类,调用的都是子类的方法,因为虚拟表里,对于相同的方法(包括名字参数返回类型等),只会有一个方法地址跟它对应,这样,被覆盖的父类方法是没办法被调用的