具有实例变量的多态性

这是我写的三个类:

公共类形状{公共 int x = 0;公共无效getArea(){System.out.println("我不知道我所在的地区!");}公共字符串 toString() {返回我是一个形状!";}公共 int getX() {返回 x;}}公共类矩形扩展形状{公共 int x = 1;公共 int getX() {返回 x;}公共无效getArea(){System.out.println("L*W");}公共字符串 toString() {return "我是一个矩形!";}}公共类测试者{公共静态无效主要(字符串[]参数){形状 s = 新形状();矩形 r = new Rectangle();System.out.println(r);System.out.println(r.x + "
");s = r;System.out.println(s);s.getArea();System.out.println(s.x);System.out.println(s.getX());}}

Tester 类的 main 方法的输出是:

<上一页>我是长方形!1我是长方形!长*宽01

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

同样作为一般规则,超类只有在该类中也声明了子类方法时才能访问其子类方法的实现?这是因为编译器将看到具有相同签名的相同数量的方法在Shape"类中(具有重写的 Rectangle 实现)并接受这些作为有效的 Shape 方法?

提前致谢,

解决方案

Java 中没有字段的多态性.但是,有继承.您实际上所做的是在 Rectangle 类中创建两个具有相同名称的字段.该字段的名称实际上是:

公共类矩形{公共 int Shape.x;公共 int Rectangle.x;}

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

在Rectangle类的整个范围内,同名的超类字段隐藏.因此,每当您在类中引用简单名称 x 或作用域名称 this.x 时,您指的是在 Rectangle<中定义的字段/代码>.您实际上也可以使用范围名称 super.x.

访问超类字段

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

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

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

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

快!您的输出现在是 1,因为编译器看到您已将字段访问范围限定为 Rectangle.

浓缩可见性规则:

您可以在 JLS,第 8.3.3.2 节

Here are three classes that I wrote:

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(r.x + "
");

        s = r;
        System.out.println(s);
        s.getArea();
        System.out.println(s.x);
        System.out.println(s.getX());
    }
}

The output from the main method of the Tester class is:

I am a rectangle!

1

I am a rectangle!

L*W

0

1

Why does s.x return 0 and not 1? As isn't the current instance of the variable a Rectangle and that class also has that same instance variable declared, or does the variable in the Rectangle class not override the previous public x variable in the Shape class as it does to the getX() method in the rectangle class thus returning 1?

Also as a general rule the superclass has access to the implementation of the its subclasses methods only if they are declared in that class as well? Is this because the compiler will see that the same amount of methods with the same signature are in the "Shape" class (with overridden Rectangle implementations) and accept those as valid Shape methods?

Thanks in advance,

解决方案

There is no polymorphism for fields in Java. There is however, inheritance. What you've effectively done is create two fields in your Rectangle class, with the same name. The names of the field are, effectively:

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

The above doesn't represent valid Java, its just an illustration of how the fields are scoped in your class

Within the entire scope of the Rectangle class, the superclass field of the same name is hidden. So anytime you reference the simple name x, or the scoped name this.x, within the class, you are referring to the field that is defined in Rectangle. You can actually access the superclass field as well, with the scoped name super.x.

Now, from outside of the class, the rules for which field is being accessed is slightly different. The scope will be determined by the compile time type of the class that the field is being referenced from. So in your code:

Shape s = new Shape();
Rectangle r = new Rectangle();

s = r;
System.out.println(s.x);

The output is 0 because the compile time type of s is Shape (not Rectangle). You can observe a change in this behavior when you do this:

Shape s = new Shape();
Rectangle r = new Rectangle();

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

Presto! Your output is now 1, because the compiler sees that you've scoped the field access to Rectangle.

To condense the rules of visibility:

You can read more about instance variable hiding in the JLS, Section 8.3.3.2

相关文章