【问题标题】:Accessing a protected variable from a subclass outside package从包外的子类访问受保护的变量
【发布时间】:2013-12-22 16:29:51
【问题描述】:

我浏览了很多网站,这些网站解释了 Java 中的访问说明符,例如 java papersjava's access specifiers,以及许多其他 stackoverflow 问题,例如 here

所有这些人都解释说受保护的成员可以被任何子类访问(也可以被包外的子类访问)并且可以被包级类访问。

在对受保护成员进行试验时,我发现我无法从包外的子类访问受保护成员。

检查下面的代码。具有受保护成员的公共类:

package com.One;

    public class ProVars {

    protected int i = 900;

    protected void foo()
    {
        System.out.println("foo");
    }

}

另一个包中的另一个公共类试图访问受保护的成员:

package com.Two;

import com.One.ProVars;

public class AnotherClass extends ProVars {

    public static void main(String[] args) {
        ProVars p = new ProVars();
        System.out.println(p.i);//the field ProVars.i is not visible(Compilation Error)
                p.foo();//the method foo() from the type ProVars is not visible

    }
}

感谢任何解释。

【问题讨论】:

  • 在我看来,真正的解释是:继承类中的静态方法(在 JAVA 中),看不到受保护的字段/方法...,即使它们管理父类的实例。这是(从我的角度来看)一个悲伤的消息。在其他语言中,这可以执行(.NET)。这样,在 JAVA 中,在哪个类中编写静态方法并不重要……您将无法访问受保护的字段/方法……(例如:对象克隆、对象复制等)

标签: java


【解决方案1】:

您正试图像使用 public 一样使用它们。他们不是public,他们是protected

示例

ProVars p = new ProVars();
p.foo(); // This will throw an error because foo() is not public.

子类使用protected方法或变量的正确用法是:

public class MyClass extends ProVars
{
     public MyClass()
     {
           System.out.println(i); // I can access it like this.
           foo(); // And this.
     }
}

为什么会这样?

因为你已经 inherited 上课了。这意味着你已经拥有了它的所有方法和它的变量。现在,因为你的方法和变量是protected,这也意味着它可以从subclass 访问。尝试将它们声明为private,看看会发生什么。

【讨论】:

  • 感谢您的明确解释。因此,我们可以访问子类中的受保护成员,但不能通过超类的对象访问它们。
  • 正确!很高兴你到了那里:)
  • 感谢您的解释,现在这对我来说很有意义,尤其是因为我在某处读过有关通过引用变量访问它的信息,但我不清楚它所引用的内容。
【解决方案2】:

即使在派生类中,您也只能从至少属于您自己的类型的限定符访问受保护的字段。

AnotherClass内部,你可以访问new AnotherClass().i,但不能访问new ProVars().i

【讨论】:

  • 感谢您的回答。你的回答是正确的,但我接受了克里斯的回答,因为他很好地阐述了它。希望你不要介意。
【解决方案3】:

如果你的主要方法不是静态的就好了。静态方法不关心继承,因此您的“扩展 ProVars”不起作用。 另一方面,这应该有效:

public class AnotherClass extends ProVars {

   public void accessProtected() {
       System.out.println(this.i);
       this.foo();
    }

    public static void main(String[] args) {
        AnotherClass p = new AnotherClass();
        p.accessProtected();
    }

}

【讨论】:

    【解决方案4】:

    与 Java protected 访问混淆是由错误的教程引起的:https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

    即使多次阅读教程也没有给出任何线索,为什么您不能从另一个包的 另一个对象 访问类 Alpha 对象的受保护成员,其AlphaSub 类是 Alpha 的子类。

    实际上,Java 语言规范解释了这一点,例如在 JLS 8 中:

    6.6.2 受保护访问的详细信息

    可以从外部访问对象的受保护成员或构造函数 仅由负责 该对象的实现

    【讨论】:

      【解决方案5】:

      你需要换行 ProVars p = new ProVars(); 进入 AnotherClass p = new AnotherClass();

      否则,您仍然在创建 ProVars 类型的对象,编译器将无法实现 AnotherClass 和 ProVars 之间的继承(导致编译错误)。

      【讨论】:

        【解决方案6】:

        在你的main()中使用子类:

        public class AnotherClass extends ProVars {
        
            public static void main(String[] args) {
            AnotherClass p = new AnotherClass();
            System.out.println(p.i);
                    p.foo();
        
        }
        
        }
        

        【讨论】:

          【解决方案7】:

          当我们说它可用于子类时,我们的意思是它可用于子类代码。但是在您的示例中,您是从外部调用受保护的方法。

          因此,虽然您的示例不起作用,但这应该

          package com.Two;
          
          import com.One.ProVars;
          
          public class AnotherClass extends ProVars {
          
          public static void main(String[] args) {
              ProVars p = new ProVars();
              p.test();
          }
          
          public test() {
                  System.out.println(this.i);)
                  this.foo();
          }
          
          
          
          }
          

          【讨论】:

            【解决方案8】:

            访问变量的代码位于静态方法中 - 静态方法不是继承受保护字段的对象的直接部分。

            尝试将代码移动到您的 AnotherClass 类中的一个方法中,然后从您的静态方法中调用该方法。

            【讨论】:

              【解决方案9】:

              在一个包中的类中声明的成员被子类继承,子类可以位于该类的同一包中,也可以位于不同的包中。

              **这里的继承意味着父类的相同受保护成员在子类中可用,使用父引用和点运算符访问如下将引发编译错误。

              ProVars p = new ProVars();
              System.out.println(p.i);// error: i has protected access in parent
              

              只需在你的子类中使用它:

              System.out.println(i); // works fine, since subclass inherit the protected 
                                        member of super class no matter whether they are in 
                                        same or different package.
              

              【讨论】:

                【解决方案10】:

                两个条件必须满足才能访问超类中的受保护字段

                1) 受保护并且只能在类的子类中的包点外部访问

                第二个总是被忽略

                2) 它们是由正在访问它们的代码实现的对象的字段。

                请参考此 JavaDocs https://docs.oracle.com/javase/specs/jls/se11/html/jls-6.html#jls-6.6.2

                【讨论】:

                  【解决方案11】:

                  这是 protected 访问修饰符的工作方式:

                  package a;
                  
                  public class Fruit {
                    protected int i = 5;
                    protected void sayHello() {
                      System.out.println("hello Fruit");
                    }
                  }
                  

                  现在像这样导入上面的:

                  package b;
                  import a.Fruit;
                  
                  public class Banana extends Fruit {
                    public static void main(String[] args) {
                  
                      Banana banana = new Banana();
                      System.out.println(banana.i);   // 5
                      banana.sayHello();              // hello Fruit
                  
                      Fruit fruit = new Fruit();
                      System.out.println(fruit.i);    // compile error
                      fruit.sayHello();               // compile error
                  
                      Fruit fb = new Banana();
                      System.out.println(fb.i);       // compile error
                      fb.sayHello();                  // compile error
                    }
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 2017-01-12
                    • 1970-01-01
                    • 2011-03-29
                    • 2023-01-13
                    • 2014-05-14
                    • 1970-01-01
                    • 1970-01-01
                    • 2018-10-30
                    • 2014-06-24
                    相关资源
                    最近更新 更多