这可能是一件坏事,正如Java 中的父类和子类是否具有相同的实例变量中所讨论的那样?. (如果更改了父变量名称怎么办?那么它就不会再被遮蔽了。)但是,我仍然很好奇静态/非静态不同的变量是否会相互遮蔽。一方面,我希望它们是相同的变量名,因此会被隐藏,但另一方面,编译器似乎可能会根据静态性区分两者。
6 回答
根据 Java 语言规范:
如果该类声明了一个具有特定名称的字段,则该字段的声明被称为隐藏了超类和该类的超接口中具有相同名称的任何和所有可访问的字段声明。
可以使用限定名称访问隐藏字段(如果它是静态的)
您可以参考“字段声明”部分。
他们将:
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
来自Java 语言规范:
如果表达式名称由单个Identifier组成,那么在Identifier出现的位置必须有一个可见的声明,表示范围内的局部变量、参数或字段 。否则,会发生编译时错误。
如果声明声明了一个 final 字段,则名称的含义就是该字段的值。否则,表达式名称的含义就是声明所声明的变量。
如果超类中的方法引用该类的特定字段(静态或其他),则只有该类对该字段的声明才会在该点范围内;子类的任何字段(静态或其他)都不在范围内。因此,该方法将始终使用超类字段,即使子类继承它并隐藏该字段。
这个答案是根据我对这个问题的新理解完全重写的。以下是我的第一个答案,留作后人。
来自Java 语言规范:
名为 n 的字段、局部变量、方法参数、构造函数参数或异常处理程序参数的声明d会隐藏在该点范围内的名为n的任何其他字段、局部变量、方法参数、构造函数参数或异常处理程序参数的声明其中d出现在d的整个范围内。
这表明无论静态性如何,编译器都需要隐藏父变量。
请注意,这些都与继承方法无关,继承方法总是使用原始变量,而不管子类是否隐藏它们。我怀疑这不是你要问的。
看看下面的代码。如果你想field
从 中访问ChildClass
,它将使用它自己的成员变量。如果field
要从访问静态SuperClass
,则必须使用 显式调用它SuperClass.field
。`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 );
}
}
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);
}
}
使用 Eclipse 的编译器,来自父类的方法仍将使用来自超类的成员变量,而不是来自子类的阴影变量,如下所示。这是 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
*/