In Java, if a child class shadows a static parent

2020-06-03 08:22发布

问题:

This is probably a bad thing to do, as discussed in Can parent and child class in Java have same instance variable?. (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.

回答1:

From The Java Language Specification:

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. 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:

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.

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.



回答2:

As per Java language specification:

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

You may refer "Field Declarations" section.



回答3:

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


回答4:

Look at the code below. If you want access field from the ChildClass, it will use its own member variable. If you want to access the static field from SuperClass, you have to call it explicitly by using SuperClass.field. The `STATIC_FIELD`` can be accessed directly since there is no ambiguity to the compiler.

  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



回答5:

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);
    }

}


回答6:

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. This is an only slightly modified version of thinksteep's answer.

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
*/