与实例变量的多态性

这是我写的三个类:

public class Shape { public int x = 0; public void getArea() { System.out.println("I don't know my area!"); } public String toString() { return "I am a shape!"; } public int getX() { return x; } } public class Rectangle extends Shape { public int x = 1; public int getX() { return x; } public void getArea() { System.out.println("L*W"); } public String toString() { return "I am a rectangle!"; } } public class Tester { public static void main(String[] args) { Shape s = new Shape(); Rectangle r = new Rectangle(); System.out.println(r); System.out.println(rx + "\n"); s = r; System.out.println(s); s.getArea(); System.out.println(sx); System.out.println(s.getX()); } } 

Tester类的main方法的输出是:

我是一个长方形!

 1

我是一个长方形!

长*宽

 0

 1

为什么sx返回0而不是1? 因为不是变量的当前实例,而是一个Rectangle,并且该类也声明了相同的实例变量,或者Rectangle类中的变量不会覆盖Shape类中的前一个公共x变量,就像它对getX()一样。矩形类中的方法因此返回1?

另外作为一般规则,超类只有在该类中声明它们时才能访问其子类方法的实现? 这是因为编译器会看到具有相同签名的相同数量的方法在“Shape”类中(具有重写的Rectangle实现)并接受它们作为有效的Shape方法吗?

提前致谢,

Java中的字段没有多态性。 然而,inheritance。 你已经有效地完成了在Rectangle类中创建两个具有相同名称的字段。 该字段的名称有效:

 public class Rectangle { public int Shape.x; public int Rectangle.x; } 

以上并不代表有效的Java,它只是说明了字段在类中的作用域

在Rectangle类的整个范围内, 隐藏了同名的超类字段。 因此,无论何时在类中引用简单名称x或作用域名称this.x ,都指的是在Rectangle定义的字段。 您实际上也可以使用作用域名称super.x访问超类字段。

现在,从类的外部,访问字段的规则略有不同。 范围将由引用该字段的类的编译时类型确定。 所以在你的代码中:

 Shape s = new Shape(); Rectangle r = new Rectangle(); s = r; System.out.println(sx); 

输出为0因为s的编译时类型是Shape (不是Rectangle )。 执行此操作时,您可以观察到此行为的更改:

 Shape s = new Shape(); Rectangle r = new Rectangle(); s = r; System.out.println(((Rectangle)s).x); 

普雷斯托! 您的输出现在为1 ,因为编译器发现您已将字段访问限定为Rectangle

浓缩可见性规则:

您可以在JLS的8.3.3.2节中阅读有关实例变量隐藏的更多信息

子类只inheritance超类中的变量和方法,而不是相反。 因此,为了使x等于1,你必须调用矩形而不是形状。除非你做其他人用铸造演示的东西,你应该尽可能地避免在实际编程中。 另外,你永远不应该使用公共实例变量! 如果你想让变量公开,至少要让它们变为静态或常量。