java 隐藏类的实例变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7794621/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 21:29:04  来源:igfitidea点击:

Hiding instance variables of a class

javaoop

提问by tskuzzy

I'm wondering why Java has this strange behavior regarding a superclass and a subclass having instance variables with the same name.

我想知道为什么 Java 对具有同名实例变量的超类和子类有这种奇怪的行为。

Let's say we have the following class definitions:

假设我们有以下类定义:

class Parent {
    int var = 1;
}

class Child extends Parent {
    int var = 2;
}

By doing this, we are supposed to have hidden the superclass's variable var. And if we do not explicitly specify a way to access Parent's varvia a supercall, then we should never be able to access varfrom an instance of a child.

通过这样做,我们应该隐藏了超类的变量var。如果我们没有明确指定通过调用访问Parent's的方法,那么我们将永远无法从子实例访问。varsupervar

But when we have a cast, this hiding mechanism breaks:

但是当我们有一个演员表时,这种隐藏机制就会中断:

Child child = new Child();
Parent parent = (Parent)child;
System.out.println(parent.var); // prints out 1, instead of 2

Doesn't this completely circumvent the whole point of field hiding? If this is the case, then doesn't that render the the idea completely useless?

这不是完全绕过了字段隐藏的全部要点吗?如果是这种情况,那么这不是使这个想法完全无用吗?

EDIT: I am referring specifically to this articlein the Java Tutorials. It mentions

编辑:我特别指的是 Java 教程中的这篇文章。它提到

Within the subclass, the field in the superclass cannotbe referenced by its simple name. Instead, the field mustbe accessed through super...

在子类中,超类中的字段不能通过其简单名称引用。相反,该字段必须通过超级访问...

From what I read there, it seems to imply that the developers of Java had some kind of technique in mind in doing this. Though I agree that it is a rather obscure concept and would probably bad practice in general.

从我在那里读到的内容,似乎暗示 Java 的开发人员在执行此操作时考虑了某种技术。尽管我同意这是一个相当晦涩的概念,并且一般来说可能是不好的做法。

回答by NPE

In Java, data members are not polymorphic.This means that Parent.varand Child.varare two distinct variables that happen to have the same name. You're not in any sense "overriding" varin the derived class; as you have discovered yourself, both variables can be accessed independently of one another.

在 Java 中,数据成员不是多态的。这意味着Parent.varChild.var是两个恰好具有相同名称的不同变量。您var在派生类中没有任何意义上的“覆盖” ;正如您自己发现的那样,这两个变量都可以相互独立地访问。

The best way forward really depends on what you're trying to achieve:

最好的前进方式实际上取决于您要实现的目标:

  1. If Parent.varshould not be visible to Child, make it private.
  2. If Parent.varand Child.varare two logically distinct variables, give them different names to avoid confusion.
  3. If Parent.varand Child.varare logically the same variable, then use one data member for them.
  1. 如果Parent.var不应该可见Child,则使其可见private
  2. 如果Parent.varChild.var是两个逻辑上不同的变量,给它们不同的名称以避免混淆。
  3. 如果Parent.varChild.var是逻辑上相同的变量,则为它们使用一个数据成员。

回答by Jon Skeet

The "point" of field hiding is merely to specify the behaviour of code which doesgive a variable the same name as one in its superclass.

字段隐藏的“点”仅仅是指定代码的行为,该行为确实赋予变量与其超类中的名称相同的名称。

It's not meant to be used as a techniqueto genuinely hide information. That's done by making the variables private to start with... I would strongly recommend using private variables in virtually all cases. Fields are an implementation detail which should be hidden from all other code.

它并不意味着用作真正隐藏信息的技术。这是通过将变量设为私有来完成的……我强烈建议在几乎所有情况下都使用私有变量。字段是一个实现细节,应该对所有其他代码隐藏。

回答by óscar López

Attributes are not polymorphic in Java, and anyway declaring a public attribute is not always a good idea. For the behavior you're looking for, it's better to use private attributes and accessor methods, like this:

属性在 Java 中不是多态的,无论如何声明一个公共属性并不总是一个好主意。对于您正在寻找的行为,最好使用私有属性和访问器方法,如下所示:

class Parent {

    private int var = 1;

    public int getVar() {
        return var;
    }

    public void setVar(int var) {
        this.var = var;
    }

}

class Child extends Parent {

    private int var = 2;

    public int getVar() {
        return var;
    }

    public void setVar(int var) {
        this.var = var;
    }

}

And now, when testing it, we get the desired result, 2:

现在,在测试时,我们得到了想要的结果,2:

Child child = new Child();
Parent parent = (Parent)child;
System.out.println(parent.getVar());

回答by Naresh Joshi

This scenario is known as variable hiding, When the child and parent class both have a variable with the same name, child class's variable hides parent class's variable and this process is called variable hiding.

这种情况称为变量隐藏,当子类和父类都有同名变量时,子类的变量隐藏父类的变量,这个过程称为变量隐藏。

In Java variables are not polymorphic and Variable Hiding is not same as Method Overriding

在 Java 中变量不是多态的,变量隐藏与方法覆盖不同

While variable hiding looks like overriding a variable similar to method overriding but it is not, Overriding is applicable only to methods while hiding is applicable variables.

虽然变量隐藏看起来像覆盖类似于方法覆盖的变量,但事实并非如此,覆盖仅适用于方法,而隐藏适用于变量。

In the case of method overriding, overridden methods completely replaces the inherited methods so when we try to access the method from parent's reference by holding child's object, the method from child class gets called.

在方法覆盖的情况下,被覆盖的方法完全取代了继承的方法,所以当我们试图通过持有子类的对象从父类的引用访问方法时,子类的方法被调用。

But in variable hiding child class hides the inherited variables instead of replacing, so when we try to access the variable from parent's reference by holding child's object, it will be accessed from the parent class.

但是在变量隐藏子类中隐藏了继承的变量而不是替换,所以当我们尝试通过持有子对象从父类引用访问变量时,它将从父类访问。

public static void main(String[] args) throws Exception {

    Parent parent = new Parent();
    parent.printInstanceVariable(); // Output - "Parent`s Instance Variable"
    System.out.println(parent.x); // Output - "Parent`s Instance Variable"

    Child child = new Child();
    child.printInstanceVariable();// Output - "Child`s Instance Variable, Parent`s Instance Variable"
    System.out.println(child.x);// Output - "Child`s Instance Variable"

    parent = child; // Or parent = new Child();
    parent.printInstanceVariable();// Output - "Child`s Instance Variable, Parent`s Instance Variable"
    System.out.println(parent.x);// Output - Parent`s Instance Variable

    // Accessing child's variable from parent's reference by type casting
    System.out.println(((Child) parent).x);// Output - "Child`s Instance Variable"
}

As we can see in above when an instance variable in a subclass has the same name as an instance variable in a superclass, then the instance variable is chosen from the reference type.

正如我们在上面看到的,当子类中的实例变量与超类中的实例变量同名时,实例变量将从引用类型中选择。

Declaring variables with the same name in both child and parent create confusion we should always avoid it so there will be no confusion. And this is why we should also always stick to General Guidelines to create POJOsand declare our variables with private access and also provide proper get/set methods to access them.

在 child 和 parent 中声明具有相同名称的变量会造成混淆,我们应该始终避免它,这样就不会有混淆。这就是为什么我们还应该始终坚持通用指南来创建 POJO并使用私有访问声明我们的变量,并提供适当的 get/set 方法来访问它们。

You can read more on my article What is Variable Shadowing and Hiding in Java.

您可以在我的文章什么是 Java 中的变量阴影和隐藏中阅读更多内容。

回答by Optimax

When you are casting, you effectively tell the compiler "I know better" - it suspends the normal strong-typing inference rules and gives you the benefit of a doubt.

当您进行转换时,您可以有效地告诉编译器“我知道得更好”——它暂停了正常的强类型推理规则,并为您提供了怀疑的好处。

By saying Parent parent = (Parent)child;you are telling the compiler "treat this object as if it were an instance of Parent".

通过说Parent parent = (Parent)child;您告诉编译器“将此对象视为父对象的实例”。

On another note, you are confusing "information hiding" principle of OO (good!) with a field-hiding side-effect (usually bad).

另一方面,您将 OO 的“信息隐藏”原则(好!)与字段隐藏副作用(通常很糟糕)混淆了。

回答by mtrovo

As you pointed out:

正如你所指出的:

we are supposed to have hidden the superclass's variable var

我们应该隐藏超类的变量 var

The main point here is Variables do notoverride as methods do, so when you call directly Child.varyou are calling a variable directly from the Child class and when you call Parent.varyou're calling a variable from the Parent class, no matter if they do have the same name.

这里的要点是变量不会像方法那样覆盖,因此当您直接调用Child.var 时,您是直接从 Child 类调用变量,而当您调用Parent.var 时,您是从 Parent 类调用变量,不如果它们确实具有相同的名称,这很重要。

As a side note I would say this is really confusing and shouldn't be allowed as valid syntax.

作为旁注,我会说这真的很令人困惑,不应该被允许作为有效的语法。