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強制轉換后
爲什麽調用變量和調用方法效果不一樣?
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強制轉換后
爲什麽調用變量和調用方法效果不一樣?
// foobarfoo
// foobarfoo
你自己说结果是这样了,那里不一样啊?
还有,不能打简体吗?
我寫錯了,不好意思
foobarfoo
foobarbar在公司,由於某種原因採用繁體的
2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。)
3. 堆:存放所有new出来的对象。
4. 静态域:存放静态成员(static定义的)
5. 常量池:存放字符串常量和基本类型常量(public static final)。
6. 非RAM存储:硬盘等永久存储空间对象的引用和对象的函数各自存放在属于这个对象的栈中,而他的FOO存放在属于他的那片常量池看完这个应该就明白了吧!
这句System.out.print(((Base) s).getFOO());之所以输入bar,是因为@Override 。
输出结果是:
foobarfoo
foobarbar
属性是静态绑定,即编译时,属性就被编译成一个相对地址,对属性的操作就是对该相对地址的操作
而方法是动态绑定,也就是编译时,为方法生成一个虚拟表(可以想象成一个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的虚拟表里去查找方法的地址,所以不管怎样强行转换为父类,调用的都是子类的方法,因为虚拟表里,对于相同的方法(包括名字参数返回类型等),只会有一个方法地址跟它对应,这样,被覆盖的父类方法是没办法被调用的