Java继承: Difference while inheriting super class members and variables

标签 java inheritance

我正在经历 Java 继承,我尝试了以下代码

class A {
    public int x = 1;

    public void print1() {
        System.out.println("Print from A");
    }
}

class B extends A {
    public int x = 2;

    public void print1() {
        System.out.println("Print from B");
    }
}

class C extends B {
    public int x = 3;

    public void print1() {
        System.out.println("Print from C");
    }

    public static void main(String aa[]) {
        C c = new C();
        ((A) c).print1();
        System.out.println(c.x);    
        System.out.println(((A) c).x);          
    }
}

输出是

Print from C
3
1

现在,我的问题是我能够从class C实例c访问class A成员x,但为什么我无法访问class方法 print1()。我知道,如果我愿意,我可以调用 new A().print1();。但是,我想直接从 C 类的实例访问它。那么通过重写方法,顶层父类的方法会在底层子类中丢失吗?然而,父类成员被保留(尽管隐藏)。为什么这样?有没有一种方法可以在类 C 中调用类 A 的方法,而无需创建 A 的实例?

最佳答案

编辑

这里发生了什么?

当你说((A)c).print1();时,JVM知道它需要调用的实际实例是print1()类型为 C,因此执行类 Cprint1() 版本。

但是当您输入((A)c).x时,您指的是状态,而不是行为,并且也使用A类型的引用。将选择哪个版本的 x 是在编译时决定的,因为编译器知道类型引用是什么(在本例中为 A)。这就是为什么您会看到 A 的状态。

此声明来自Java doc您可能也会感兴趣:

Within a class, a field that has the same name as a field in the superclass hides the superclass's field, even if their types are different. Within the subclass, the field in the superclass cannot be referenced by its simple name. Instead, the field must be accessed through super, which is covered in the next section. Generally speaking, we don't recommend hiding fields as it makes code difficult to read.

<小时/>

为什么会这样?

回答您的问题:

问题 1:

my question is that I am able to access class A member x from class C instance c

关于变量x,由于它被声明为public,因此无法对其应用业务验证。此外,将其声明为 public 的开发人员意识到现在无法应用封装的概念(显然不建议这样做)。因此,允许使用子实例访问父级的状态没有什么坏处。因此,通过使用((A)c).x,您可以从A类访问x

问题2:

However, the parent class members are retained (although hidden). Why so?

这是因为 Java 不允许您任意使用 super.super.super.. 来访问继承层次结构中任何父级的行为。其背后的原因是为了保持封装性。您只能使用 super 关键字访问直接父类的行为,但不能超出此范围。

为了更多地解释它,假设您有类 B 的实现,例如:

class B extends A {
    public int x = 2;

    public void print1() {
        if(x >= 2) {
            System.out.println("Print from B");
        }
    }
}

现在,如果允许 super.super ,您可以轻松绕过 B 类的 print1() 方法中的验证,并可以调用 AC 实例中的 print1() 方法。

问题3:

However, the parent class members are retained (although hidden). Why so?

正如前面提到的,保留封装。

问题 4:

And is there a way to call a method from class A in class C without creating an instance of A?

因此无法使用 C 的实例从 A 访问 print1()

关于Java继承: Difference while inheriting super class members and variables,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36597629/

相关文章:

java - 为什么我的继承申请不起作用?

java.nio.charset.IllegalCharsetNameException : 'ISO-8859-1'

java - maven 找不到包 atlassian

ios - 子类化 MKAnnotation 导致 Set 集合不起作用

java - Java Generic Type 参数可以扩展另一个 Type 参数和附加的有界类型吗?

c++ - 通过抽象类将参数传递给祖父类的构造函数

java - 在保存 Activity 中打开另一个共享首选项会替换旧的共享首选项

java - 如何将加载指示器添加到 Android Picasso?

java - 一个在某个网站上搜索的java程序

python - 实例化从 cython 中的类派生的 C++ 结构