2012-01-06 136 views
0

考虑以下非法代码: -我不明白这种继承功能

class WrongCode{ 
    int i; 
    static int i; 
} 

这里,编译器说,我们在同一个班级重复的字段。

现在,考虑在同一文件中的以下类。

class Parent{ 
    int i = 10; 
} 

class Child extends Parent{ 
    static int i = 100; 
} 

public class Main{ 
    public static void main(String ... aaa){ 
     Parent ob = new Child(); 
     System.out.println(ob.i); // This prints Parent's i 
    } 
} 

由于实际对象是Child,因此不应该参考Child's i吗?如果它指的是家长的“我”,那么在某种程度上,它也会在其自己的班级中拥有家长的“我”以及不允许的自己的静态“我”。

孩子静态我overshadows父母我。父母的我不是静态的,那么它如何直接使用实例而不是className来访问?

+3

尝试'Child ob = new Child();'得到派生的'i'。 – 2012-01-06 06:44:06

+0

在Child类中,让我非静态的,看看会发生什么?它仍然应该打印父母我。 – 2012-01-06 06:47:13

+0

@βнɛƨнǤʋяʋиɢ让我在Child中是非静态的,结果相同。 – whitehat 2012-01-06 06:49:30

回答

0

ob,孩子的static int i是不可见的,因为ob的类型是父母的,不论它是如何被实例化(基类或派生类)。

这就是为什么你的价值为,即Parent s i值。

0

Java允许您的类拥有自己的变量,该变量与父类中的变量具有相同的名称。但它不能让你随机重新定义父变量,因为这会导致其他东西被破坏。所以它做什么......当你有一个声明为父类的变量obj时,即使它拥有一个子类的实例,obj.i将引用父类的i而不是孩子的类。

0

当您访问类成员字段(实例变量),如ob.i.您将从编译时已知的类中获得结果,而不是在运行时已知的结果。这就是为什么你有价值为10,这是父母的价值。

对于方法调用,它们在运行时分派给实际类的参考点的对象。

关于阴影这里是Java的郎规范说:

如果类声明的字段具有特定名称,那么该字段的声明说,隐藏字段的任何和所有可访问声明具有相同名称在超类和类的超接口中。

隐藏字段可以通过使用一个合格的名称(如果它是静态的)访问

language spec

你可以参考“字段声明”一节。

0

实际上,它的多态性和ob只能访问父类字段和行为,如果有...

1

它在这里是没有办法System.out.println(ob.i);实现可以打印Childi是很重要的:它只知道ob是声明类型Parent的,不在于它是与实际Child实例化。因此,如果Parent没有任何i,则会出现编译错误。如果父母有i,则会打印。

我已经看到它在SO上提到通过实例访问类变量(即ob.i相当于Parent.i)应该被认为是Java的严重设计缺陷。我同意它有时会令人困惑。无论如何,你的父母和孩子也可以有一个非静态的i,它不一定是相同的。上面的论点应该适用于推理在哪种情况下打印哪一个。