package p1;
public class MyClass1 {
protected static String str = "ss1";
}
package p2;
import p1.MyClass1;
public class MyClass2 extends MyClass1 {
public static void test(){
MyClass1 mc1 = new MyClass1();
System.out.println(mc1.str);
}
}
据我所知,如果将String声明为protected,则print语句将不起作用,因为从另一个包中看不到它。但是,为什么声明为静态保护时它会起作用?
答案 0 :(得分:3)
静态修饰符与可见性无关,因此不会发生任何变化。您无法从不同的包中访问 protected 成员(即字段,方法),无论它是否为静态。
但在你的情况下,MyClass2扩展了MyClass1。您可以从超类访问受保护的成员。不过, static 与此无关。
编辑:
嗯,这是一个非常有趣的案例,因为涉及两个不同的事情: 1)从不同包中的子类访问受保护的成员, 2)语法技巧允许您访问静态(类)成员,如实例成员。
我将扩展您的示例以显示您在此代码中实际执行的操作:
package p1;
public class MyClass1 {
protected String protectedString = "example";
protected static String protectedStaticString = "example";
}
package p2;
import p1.MyClass1;
public class MyClass2 extends MyClass1 {
public void testProtected() {
MyClass1 otherMC1 = new MyClass1();
MyClass2 otherMC2 = new MyClass2();
String testProtected;
testProtected = this.protectedString; // OK, protectedString is inherited, so it's instance member of this class
testProtected = super.protectedString; // OK, it's also instance member of superclass
testProtected = otherMC1.protectedString; // ERROR. You can't access protected members of other instance of superclass
testProtected = otherMC2.protectedString; // OK. As it's inherited member of MyClass2, you can access it if it belongs to other instance of your class
}
public void testProtectedStatic() {
MyClass1 otherMC1 = new MyClass1();
MyClass2 otherMC2 = new MyClass2();
String testProtectedStatic;
testProtectedStatic = this.protectedStaticString; // OK - syntax trick
testProtectedStatic = super.protectedStaticString; // OK - syntax trick
testProtectedStatic = otherMC1.protectedStaticString; // OK - syntax trick
testProtectedStatic = otherMC2.protectedStaticString; // OK - syntax trick
testProtectedStatic = MyClass1.protectedStaticString; // OK - you can access protected static members from superclass
testProtectedStatic = MyClass2.protectedStaticString; // OK - this also static member of your class
}
}
现在,'语法技巧'是什么。编译器允许您访问静态成员,就像它们是实例成员一样:
MyClass mc = new MyClass();
Object o = mc.STATIC_FIELD;
但实际编译为字节码的是什么:
MyClass mc = new MyClass();
Object o = MyClass.STATIC_FIELD;
以这种方式访问静态成员被认为是不好的做法,因为它具有误导性。您应该始终以静态方式访问静态成员,以避免在阅读代码时出现混淆。
这就是你的情况。有静态字段以非静态方式访问,因此它看起来像实例字段。删除 static 修饰符后,它将成为实例成员。访问此字段的方式已更改,但由于您的 object.staticField 语法,您没有注意到这一点。
答案 1 :(得分:1)
正如所指出的,静态与可见性无关。
在您的情况下,'str'被标记为受保护,这意味着有两种类可以看到它: - 同一个包中的类 - 扩展MyClass1的类
您的代码有效,因为MyClass2扩展了MyClass1。
答案 2 :(得分:0)
它与 static 无关。您可以访问该成员,因为MyClass2扩展了MyClass1
答案 3 :(得分:0)
这是一个有趣的规则:您可以访问超类中定义的受保护实例变量,但不能使用私有实例变量访问该类的子类中的私有实例变量。 e.g。
public class Super {
private String str;
}
public class Sub extends Super {
public void getStr(){
return str; // not allowed.
}
}
但是,如果使用以下内容,则允许这样做:
public class Super {
protected String str;
}
public class Sub extends Super {
public void getStr(){
return str; // allowed.
}
}
答案 4 :(得分:0)
public
表示所有课程都可以看到。protected
表示包和所有子类可见。private
表示它只在自己的班级中可见。有关详细信息,请参阅Controlling Access to Members of a Class。