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); 

         }

}

据我了解,如果字符串被声明为受保护,则打印语句将不起作用,因为它在其他包中不可见。但是为什么当被声明为 static protected 时它会起作用?

4

5 回答 5

3

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

但在您的情况下,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语法,您没有注意到这一点。

于 2013-04-05T19:50:19.033 回答
1

正如所指出的,静态与可见性无关。

在您的情况下,“str”被标记为受保护,这意味着有两种类型的类可以看到它: - 同一包中的类 - 扩展 MyClass1 的类

您的代码有效,因为 MyClass2 扩展了 MyClass1。

于 2013-04-05T19:54:17.377 回答
0

它与它是否是静态的无关。您可以访问该成员,因为 MyClass2 扩展了 MyClass1

于 2013-04-05T19:52:26.387 回答
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.
    }
}
于 2013-04-05T19:55:07.587 回答
0
  • public意味着它对所有类都可见。
  • protected意味着它对包和所有子类可见。
  • (无修饰符)意味着它仅对包可见。
  • private意味着它只在自己的类中可见。

有关详细信息,请参阅控制对类成员的访问

于 2013-04-05T19:55:44.583 回答