Java 保护区的可见性
据我所知,如果字符串被声明为受保护,则print语句将不起作用,因为它在其他包中不可见。但是,当声明为静态保护时,为什么它可以工作呢?静态修饰符与可见性无关,所以不会发生任何更改。您不能从不同的包访问受保护的成员(即字段、方法),无论它是否是静态的 但在您的情况下,MyClass2扩展了MyClass1。您可以从超类访问受保护的成员。不过,静态与此无关 编辑: 这是一个非常有趣的案例,因为它涉及两个不同的方面: 1) 从不同包中的子类访问受保护的成员, 2) 允许您访问静态(类)成员(如实例成员)的语法技巧 我将扩展您的示例,以显示您在这段代码中实际在做什么:Java 保护区的可见性,java,Java,据我所知,如果字符串被声明为受保护,则print语句将不起作用,因为它在其他包中不可见。但是,当声明为静态保护时,为什么它可以工作呢?静态修饰符与可见性无关,所以不会发生任何更改。您不能从不同的包访问受保护的成员(即字段、方法),无论它是否是静态的 但在您的情况下,MyClass2扩展了MyClass1。您可以从超类访问受保护的成员。不过,静态与此无关 编辑: 这是一个非常有趣的案例,因为它涉及两个不同的方面: 1) 从不同包中的子类访问受保护的成员, 2) 允许您访问静态(类)成员(如实例成员
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);
}
}
现在,什么是“语法技巧”。编译器允许您像访问实例成员一样访问静态成员:
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;
以这种方式访问静态成员被认为是不好的做法,因为它具有误导性。您应该始终以静态方式访问静态成员,以避免在读取代码时出现混淆
这就是你的情况。静态字段是以非静态方式访问的,所以它看起来像实例字段。删除静态修改器后,它将成为实例成员。访问此字段的方式已更改,但由于object.staticField语法的原因,您没有注意到。静态修饰符与可见性无关,因此不会发生任何更改。您不能从不同的包访问受保护的成员(即字段、方法),无论它是否是静态的
但在您的情况下,MyClass2扩展了MyClass1。您可以从超类访问受保护的成员。不过,静态与此无关
编辑:
这是一个非常有趣的案例,因为它涉及两个不同的方面:
1) 从不同包中的子类访问受保护的成员,
2) 允许您访问静态(类)成员(如实例成员)的语法技巧
我将扩展您的示例,以显示您在这段代码中实际在做什么:
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);
}
}
现在,什么是“语法技巧”。编译器允许您像访问实例成员一样访问静态成员:
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;
以这种方式访问静态成员被认为是不好的做法,因为它具有误导性。您应该始终以静态方式访问静态成员,以避免在读取代码时出现混淆
这就是你的情况。静态字段是以非静态方式访问的,所以它看起来像实例字段。删除静态修改器后,它将成为实例成员。访问此字段的方式已更改,但您没有注意到,这是因为您的object.staticField语法。它与是否为静态字段无关。您可以访问该成员,因为MyClass2扩展了MyClass1它与它是否为静态无关。您可以访问该成员,因为MyClass2扩展了MyClass1,正如前面指出的,static与可见性无关 在您的例子中,“str”被标记为protected,这意味着有两种类型的类可以看到它: -同一包中的类 -扩展MyClass1的类
您的代码之所以有效,是因为MyClass2扩展了MyClass1。正如前面指出的,静态与可见性无关 在您的例子中,“str”被标记为protected,这意味着有两种类型的类可以看到它: -同一包中的类 -扩展MyClass1的类
您的代码之所以有效,是因为MyClass2扩展了MyClass1。这里有一条有趣的规则:您可以访问在超类中定义的受保护实例变量,但不能访问该类的子类中具有私有实例变量的私有实例变量。e、 g
MyClass mc = new MyClass();
Object o = MyClass.STATIC_FIELD;
但是,如果使用了以下内容,则允许:
public class Super {
private String str;
}
public class Sub extends Super {
public void getStr(){
return str; // not allowed.
}
}
这里有一条有趣的规则:您可以访问在超类中定义的受保护的实例变量,但不能使用私有实例变量访问该类的子类中的私有实例变量。e、 g
MyClass mc = new MyClass();
Object o = MyClass.STATIC_FIELD;
但是,如果使用了以下内容,则允许:
public class Super {
private String str;
}
public class Sub extends Super {
public void getStr(){
return str; // not allowed.
}
}
表示它对所有类都可见public
表示包和所有子类都可以看到它protected
- (无修改器)表示它仅对包可见
表示它只在自己的类中可见private
表示它对所有类都可见public
表示包和所有子类都可以看到它protected
- (无修改器)表示它仅对包可见
表示它只在自己的类中可见private
有关更多信息,请参阅。没错,我刚刚注意到了这一点,并编辑了答案。您可以通过继承从不同的包中访问。谢谢您的回答。但是,如果只保护字符串str,为什么它不起作用呢?我仍然在从子类访问它。对不起,我不明白什么对你有效,什么对你无效。你能举个例子,告诉我你犯了什么错误吗?对不起,我没说清楚。上面的代码编译得很好。但是,如果我将字符串ss的访问修饰符从“static protected”更改为“protected”,我会得到一个编译时错误:str在MyClass1 System.out.println(mc1.str)中具有受保护的访问权限^没错,我刚刚注意到了这一点,我编辑了答案。你可以通过继承从不同的包访问。谢谢你的答案。但是,如果只保护字符串str,为什么它不起作用呢?我仍然在从子类访问它。对不起,我不明白什么对你有效,什么对你无效。你能举个例子,告诉我