2013-04-05 63 views
0
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); 

     } 

} 

据我所知,如果字符串被声明为受保护的,因为它从另一个包中不可见,则print语句将不起作用。但是,为什么当声明为静态保护时它工作?受保护字段的可见性

回答

3

静态修饰符与可见性无关,所以没有什么会改变。不能访问受保护的成员(即字段,方法)来自不同的包,无论它是否是静态的。

但在你的情况下,MyClass2扩展了MyClass1。您可以从超类访问受保护的成员。仍然,静态与此无关。

编辑:

那么,这是因为涉及两个不同的东西非常有趣的案例: 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; 

访问静态成员以这种方式被认为是不好的做法,因为这是误导。您应该始终以静态方式访问静态成员,以避免在阅读代码时出现混淆。

这是什么在你的情况。有静态字段以非静态方式访问,所以它看起来像实例字段。当您删除静态修饰符时,它成为实例成员。访问该字段的方式发生了变化,但您没有注意到,因为您的语法为object.staticField

+0

的确如此,我刚刚注意到了这一点,并且我编辑了答案。 – 2013-04-05 19:53:29

+0

您可以通过继承从不同的包进行访问。 – elias 2013-04-05 19:54:01

+0

感谢您的回答。但是,如果String str只受保护,为什么它不起作用呢?我仍然从子类访问它。 – user2250448 2013-04-05 22:16:35

0

它与静态或没有关系。您可以访问该成员,因为MyClass2扩展了MyClass1

1

如前所述,静态与可见性无关。

在你的情况,“STR”被标记为受保护的,这意味着2种类型的类可以看到: - 类在同一个包 - 扩展MyClass1的

你的代码的工作,因为MyClass2扩展类MyClass1的。

0

这是一个有趣的规则:您可以访问在超类中定义的受保护的实例变量,但不能使用私有实例变量访问该类的子类中的私有实例变量。例如

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. 
    } 
} 
0
  • public意味着它的所有类可见。
  • protected表示它对包和所有子类可见。
  • (无修饰符)表示仅对包装可见。
  • private意味着它只在其自己的类中可见。

请参阅Controlling Access to Members of a Class了解更多信息。