[英]Overridden methods and variables - Inconsistent behavior
当可见性更改为private
时,以下代码在重写的方法getName()
上产生编译时错误
这是可以理解的,但奇怪的是,被覆盖的变量不会产生任何错误。
class Base {
public String getName() {
return "Base";
}
public String className = "Base";
}
class Derived extends Base {
private String getName() { //Not compiling
return "derived";
}
private String className = "Derived"; //Compiling successfully
}
public class Test{
public static void main(String[] args) {
System.out.println((new Derived()).className);// Gives compilation error
}
有人可以帮助我了解为什么会这样吗?
虽然我们尝试在main()
编译中访问私有变量失败,但是在方法本身上,当我将访问类型从public减少为private时,它成功编译也应该在那里失败 。
标准(§8.4.8.3)禁止使用较弱的访问修饰符覆盖方法:
覆盖或隐藏方法的访问修饰符(第6.6节)必须至少提供与覆盖或隐藏方法相同的访问权限,如下所示:
如果覆盖或隐藏方法是公共的,则覆盖或隐藏方法必须是公共的; 否则,将发生编译时错误。
如果覆盖或隐藏方法受到保护,则覆盖或隐藏方法必须受到保护或公开; 否则,将发生编译时错误。
如果覆盖或隐藏方法具有默认(程序包)访问权限,则覆盖或隐藏方法不能为私有方法;否则,不能为私有方法。 否则,将发生编译时错误。
这确保了基类提供的任何方法也可以在同一上下文中的派生类上调用。
变量不能被覆盖。 Base.className
和Derived.className
是两个不同的变量。 因此,在Derived
具有相同名称和不同访问修饰符的变量是完全有效的。
即此代码将打印false
:
class Base{
public String str = "hello";
}
class Derived extends Base{
private String str = "whatever";
public Derived(){
super.str = "abc";
str = "def";
}
void foo(){
System.out.println(str.equals(super.str));
}
}
public static void main(String[] args){
new Derived().foo();
}
相关的jls部分:
§6.3和§6.4中指定了字段声明的范围和阴影。
如果类声明了具有特定名称的字段,则称该字段的声明隐藏了超类和该类的超接口中所有相同名称的字段的所有可访问声明。
在这方面,字段的隐藏不同于方法的隐藏(第8.4.8.3节),因为在字段隐藏中静态字段和非静态字段之间没有区别,而在方法隐藏中静态方法和非静态方法之间没有区别。
如果隐藏字段是静态的,则可以使用限定名对其进行访问(第6.5.6.2节),也可以使用包含关键字super(第15.11.2节)或强制转换为超类类型的字段访问表达式进行访问。
在这方面,字段的隐藏类似于方法的隐藏。
如果字段声明隐藏了另一个字段的声明,则两个字段不必具有相同的类型。
和阴影(§6.4.1) :
在整个d范围内,名为n的字段或形式参数的声明d在整个d范围内,在d发生时在范围内的任何其他名为n的变量的声明。
您不能override
字段,而只能hide
其hide
。 这意味着您只需创建具有相同名称的新变量即可。
从JLS 字段声明
如果类声明了具有特定名称的字段,则称该字段的声明隐藏了超类和该类的超接口中所有相同名称的字段的所有可访问声明。
无法使用限制性更强的访问说明符覆盖方法(例如,当超类中的方法为public
时,则为private
)。 如果有可能,您将能够做一些奇怪的事情,例如调用不应访问的private
方法:
Derived object1 = new Derived();
// Will give an error, because getName() is private
String name1 = object1.getName();
Base object2 = new Derived();
// Should this be possible because getName() is public in Base?
// (Note that object2 is of type Base).
// But that would be strange, because the method is overridden
// in Derived, so we would be calling a private method here that
// should not be accessible from the outside!
String name2 = object2.getName();
在将超类的方法重写为子类时,访问级别可以保持不变,也可以更宽/更宽(即,增加子类中重写方法的访问可见性)。
因此,如果您的基类方法是公共方法,则不能将其重写为私有方法或受保护方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.