2 z55887 z55887 于 2016.02.01 22:17 提问

stackoverflow上面的java的域不能“重写”问题
package test;

class A 
{
    int x = 5;
} 
class B extends A 
{
    int x = 6;
} 
public class CovariantTest 
{
    public A getObject() 
    {
       return new A();
    } 
    public static void main(String[]args) 
    {
       CovariantTest c1 = new SubCovariantTest();
       System.out.println(c1.getObject().x);
    }
}

class SubCovariantTest extends CovariantTest 
{
    public B getObject() 
    {
       return new B();
    }
}

最后输出的答案是5不是6
stackoverflow上面的解释我看了还是不太理解。
1.成员变量是编译时决定我了解,但这与“c1.getObject().x”有什么关系?毕竟c1.getObject()返回的是类B的对象呀?
2.解释里提到了隐藏域,子类的域会隐藏父类同名域,和重写是不一样的。我不太明白这个与答案有什么联系?

stackoverflow的问题地址:
http://stackoverflow.com/questions/12589274/slight-confusion-regarding-overriding-where-variables-are-concerned

1个回答

caozhy
caozhy   Ds   Rxr 2016.02.01 22:58
已采纳

提到了隐藏域,子类的域会隐藏父类同名域,和重写是不一样的。我不太明白这个与答案有什么联系
这就是说两个变量都叫x,但是是两个我完全不同的变量,既然不同的变量,干脆我们就用不同的名字。
看下面的代码,我把派生类的x修改为y,使得派生类的x叫做y

 /* package whatever; // don't place package name! */

import java.util.*;
import java.lang.*;
import java.io.*;

class A 
{
    int x = 5;
} 
class B extends A 
{
    int y = 6;
} 

class SubCovariantTest extends CovariantTest 
{
    public B getObject() 
    {
        System.out.println("sub getobj");
       return new B();
    }
}
/* Name of the class has to be "Main" only if the class is public. */
class CovariantTest 
{
    public A getObject() 
    {
        System.out.println("ct getobj");
       return new A();
    } 

    public static void main (String[] args) throws java.lang.Exception
    {
        // your code goes here
        CovariantTest c1 = new SubCovariantTest();
        System.out.println(c1.getObject().y);
    }
}

现在这代码没办法编译了。

System.out.println(c1.getObject().x);
可以编译。

说明派生类定义的那个变量,编译器根本就不承认它的存在。为什么如此?因为

public B getObject() 
{
    System.out.println("sub getobj");
   return new B();
}

你一厢情愿把返回值写成B,但是它仍然只能返回A

这个叫做协变式覆盖

http://blog.csdn.net/kiss_the_sun/article/details/7846413

所以它返回的其实还是被当作A,既然是A,那么显然B定义的类型不作数了。

z55887
z55887 嗯嗯,我彻底明白了,谢谢了
接近 2 年之前 回复
caozhy
caozhy 回复大树先生: 如果问题解决了,麻烦点下我回答右边的采纳。如果还有不明白,欢迎再次提问。谢谢。
接近 2 年之前 回复
caozhy
caozhy 回复大树先生: getobject是运行时调用的,返回的是真实的类型。编译器只能看到a类型,绑定的也是a的x。
接近 2 年之前 回复
z55887
z55887 嗯嗯,我明白这点了。能够帮忙回答一下我的第一点疑问吗?谢谢了
接近 2 年之前 回复
caozhy
caozhy 回复大树先生: 根本两个x是两个变量,没有什么关系,更不存在覆盖。应该说“隐藏”,好比你的成员变量和函数参数如果两个变量同名,你不用this.,访问的是参数变量,参数变量“挡住”了成员变量,是一个道理。
接近 2 年之前 回复
z55887
z55887 2.隐藏域等于新创建了一个域,那么我能理解重写就是子类把父类的域“覆盖了”吗?也就说堆中父类域在的那块空间放着子类的值。而隐藏域堆中父类域在的空间没有改变,而是新加了一段空间存储子类同名域,是这么个原理吗?最近看这些基础概念,有些混淆,谢谢指点了
接近 2 年之前 回复
z55887
z55887 1.关于协变式覆盖,我能理解成子类的返回类型是父类返回类型的子类,所以“c1.getObject()”在编译期看成了A类,是吗?因为输出“c1.getObject().getClass().getName()”会是B类
接近 2 年之前 回复
z55887
z55887 谢谢代码规范的指正~还是有些不明白的地方:
接近 2 年之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!