简体   繁体   English

在Java中,如果子类使用实例子变量隐藏静态父变量,哪个变量将继承方法使用?

[英]In Java, if a child class shadows a static parent variable with an instance child variable, which variable will inherited methods use?

This is probably a bad thing to do, as discussed in Can parent and child class in Java have same instance variable? 这可能是一件坏事,如在Java中的父级和子级类中讨论的具有相同的实例变量? . (What if the parent variable name is changed? Then it will not be shadowed anymore.) However, I am still curious whether variables that are differently static/nonstatic will shadow each other. (如果父变量名称被更改怎么办?那么它将不再被遮蔽。)但是,我仍然好奇不同的静态/非静态变量是否会相互影响。 On one hand I would expect they are the same variable name so would be shadowed, but on the other hand it seems like the compiler might distinguish between the two based on staticness. 一方面,我希望它们是相同的变量名称,因此将被遮蔽,但另一方面,似乎编译器可能基于静态区分这两者。

As per Java language specification: 根据Java语言规范:

If the class declares a field with a certain name, then the declaration of that field is said to hide any and all accessible declarations of fields with the same name in superclasses, and superinterfaces of the class. 如果类声明了具有特定名称的字段,那么该字段的声明将被称为隐藏超类中具有相同名称的字段的任何和所有可访问声明 ,以及该类的超接口。

A hidden field can be accessed by using a qualified name (if it is static) 可以使用限定名称访问隐藏字段(如果它是静态的)

JVM Specification JVM规范

You may refer "Field Declarations" section. 您可以参考“现场声明”部分。

they will: 他们会:

class Parent {
    static String x="static in parent";
    String y="instance in parent";
}
class Child extends Parent {
    static String y="static in child";
    String x="instance in child";
    void foo() {
        System.out.println("x "+x);
        System.out.println("super.x " + super.x); 
        System.out.println("y "+y);
        System.out.println("super.y " + super.y); 
    }
}
public class Main {
    public static void main(String[] args) {
        Parent parent=new Parent();
        Child child=new Child();
        System.out.println("Parent.x "+Parent.x);
        System.out.println("parent.x "+Parent.x); 
        System.out.println("parent.y "+parent.y);
        System.out.println("child.x "+child.x);
        System.out.println("Child.y "+Child.y);
        System.out.println("child.y "+child.y);
        System.out.println("(Parent)child).x "+((Parent)child).x);
        System.out.println("(Parent)child).y "+((Parent)child).y);
        child.foo();
    }
}



Parent.x static in parent
parent.x static in parent
parent.y instance in parent
child.x instance in child
Child.y static in child
child.y static in child
(Parent)child).x static in parent
(Parent)child).y instance in parent
x instance in child
super.x static in parent
y static in child
super.y instance in parent

From The Java Language Specification : 来自Java语言规范

If an expression name consists of a single Identifier , then there must be exactly one visible declaration denoting either a local variable, parameter or field in scope at the point at which the the Identifier occurs. 如果表达式名称由单个标识符组成 ,则必须只有一个可见声明,表示标识符出现点的范围内的局部变量,参数或字段。 Otherwise, a compile-time error occurs. 否则,发生编译时错误。

If the declaration declares a final field, the meaning of the name is the value of that field. 如果声明声明了final字段,则name的含义是该字段的值。 Otherwise, the meaning of the expression name is the variable declared by the declaration. 否则,表达式名称的含义是声明声明的变量。

If a method in a superclass refers to a particular field (static or otherwise) of that class, only that class's declaration of the field will be in scope at that point; 如果超类中的方法引用该类的特定字段(静态或其他),那么该字段的该字段声明将在该范围内; any fields (static or otherwise) of subclasses will not be in scope. 子类的任何字段(静态或其他)都不在范围内。 Therefore, the method will always use the superclass field, even if a subclass inherits it and shadows that field. 因此,该方法将始终使用超类字段,即使子类继承它并且阴影该字段。

This answer is completely rewritten based on my new understanding of the question. 这个答案完全是基于我对这个问题的新理解而改写的。 Below is my first answer, kept for posterity. 以下是我的第一个答案,留给后人。

From The Java Language Specification : 来自Java语言规范

A declaration d of a field, local variable, method parameter, constructor parameter or exception handler parameter named n shadows the declarations of any other fields, local variables, method parameters, constructor parameters or exception handler parameters named n that are in scope at the point where d occurs throughout the scope of d . 名为n的字段,局部变量,方法参数,构造函数参数或异常处理程序参数的声明d隐藏了该点范围内的任何其他字段,局部变量,方法参数,构造函数参数或名为n的异常处理程序参数的声明其中d发生在整个d的范围。

This suggests that compilers are required to shadow parent variables, regardless of staticness. 这表明编译器需要对父变量进行阴影处理,而不管静态性如何。

Note that none of this is relevant to inherited methods, which always use the original variables regardless of whether a subclass shadows them. 请注意,这些都与继承的方法无关,无论子类是否影响它们,它们始终使用原始变量。 I suspect this isn't what you meant to ask. 我怀疑这不是你要问的问题。

Look at the code below. 看下面的代码。 If you want access field from the ChildClass , it will use its own member variable. 如果你想从ChildClass访问field ,它将使用自己的成员变量。 If you want to access the static field from SuperClass , you have to call it explicitly by using SuperClass.field . 如果要从SuperClass访问静态field ,则必须使用SuperClass.field显式调用它。 The `STATIC_FIELD`` can be accessed directly since there is no ambiguity to the compiler. 可以直接访问`STATIC_FIELD``,因为编译器没有歧义。

  public class SuperClass{
    static String field = "staticField1";
    static String STATIC_FIELD = "staticField2";

    //not possible to have a member field in this class -> compile error
    //String field = "memberField"; is not possible
    public SuperClass() {
      System.out.println( "field = " + field );

    }
  }
  public class ChildClass extends SuperClass{
    String field = "memberField";

    public ChildClass() {
      System.out.println( "field = " + field );//access to member field
      //need to explicitly call SuperClass.field to access the static variable
      System.out.println( "SuperClass.field = " + SuperClass.field );
      //no need to do this when there is no amibiguity
      System.out.println( "STATIC_FIELD = " + STATIC_FIELD );
    }
  }

See also 15.11.1 and 15.11.2 in here and 8.3 in here 另见15.11.1 15.11.2和这里和8.3在这里

public class Test {

    public static int MYNUMBER = 5;

    public Test() {
    }
}

public class TestChild extends Test {

    public int MYNUMBER = 8;

    public TestChild() {
    }
}

public class Main {

    public static void main(String[] args) {
        TestChild testChild = new TestChild();

        // This would print out 8
        System.out.println("in main test child: " + testChild.MYNUMBER);

        // This won't even compile if the MYNUMBER variable is overshadowed
        // If the MYNUMBER variable is not overshadowed it
        // would compile and
        // print out 5
        // If we make MYNUMBER static also on TestChild,
        // it would compile and print out 8
        System.out.println("in main TestChild.MYNUMBER " + TestChild.MYNUMBER);

        // This would print out 5
        System.out.println(Test.MYNUMBER);
    }

}

With Eclipse's compiler, methods from the parent class will still use the member variables from the superclass, not the shadowed variables from the child class, as shown below. 使用Eclipse的编译器,父类中的方法仍将使用超类中的成员变量,而不是子类中的阴影变量,如下所示。 This is an only slightly modified version of thinksteep's answer. 这是thinksteep的答案的一个稍微修改过的版本。

class Parent {
    static String x ="static in parent";
    String y="instance in parent";

    void bar() {
        System.out.println("x "+ x);
        System.out.println("y "+ y);
    }
}

class Child extends Parent {
    static String y ="static in child";
    String x="instance in child";

    void foo() {
        System.out.println("x "+x);
        System.out.println("super.x " + super.x); 
        System.out.println("y "+y);
        System.out.println("super.y " + super.y); 
    }
}

public class Main {
    public static void main(String[] args) {
        Parent parent=new Parent();
        Child child=new Child();
        System.out.println("Parent.x "+Parent.x);
        System.out.println("parent.x "+Parent.x); 
        System.out.println("parent.y "+parent.y);
        System.out.println("child.x "+child.x);
        System.out.println("Child.y "+Child.y);
        System.out.println("child.y "+child.y);
        System.out.println("(Parent)child).x "+((Parent)child).x);
        System.out.println("(Parent)child).y "+((Parent)child).y);
        System.out.println("Member variable visibility in parent:");
        parent.bar();
        System.out.println("Member variable visibility in child:");
        child.foo();
        System.out.println("Member variable visibility in inherited methods:");         
        child.bar();

        System.exit(0);
}

/* Output:
Parent.x static in parent
parent.x static in parent
parent.y instance in parent
child.x instance in child
Child.y static in child
child.y static in child
(Parent)child).x static in parent
(Parent)child).y instance in parent
Member variable visibility in parent:
x static in parent
y instance in parent
Member variable visibility in child:
x instance in child
super.x static in parent
y static in child
super.y instance in parent
Member variable visibility in parent methods:
x static in parent
y instance in parent
*/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM