【问题标题】:Protected member access from different packages in java - a curiosity [duplicate]java中不同包的受保护成员访问-好奇心[重复]
【发布时间】:2011-07-30 13:43:23
【问题描述】:
package packageOne;
public class Base
{
    protected void display(){
        System.out.println("in Base");
    }
}


package packageTwo;
public class Derived extends packageOne.Base {
    public void show(){
        new Base().display(); //this is not working throws compilation error that display() from the type Base is not visible
        new Derived().display(); //is working
        display(); //is working
    }
}

这两个包位于两个不同的文件中。但是为什么会有这种行为呢?

【问题讨论】:

    标签: java protected


    【解决方案1】:

    protected 允许从子类和从同一包中的其他类访问。这就是为什么任何Derived 类实例都可以访问Base 中受保护的方法。

    另一行创建了一个Base 实例(不是Derived 实例!!)。并且仅允许从同一包的对象访问该实例的受保护方法。


    display();
    

    -> 允许,因为调用者,Derived 的实例可以访问其子类的受保护成员和字段,即使它们位于不同的包中

    new Derived().display();
    

    -> 允许,因为您在Derived 的实例上调用该方法,并且该实例可以访问其子类的受保护方法

    new Base().display();
    

    -> 不允许 因为调用者的(this 实例)类没有像Base 类定义在同一个包中,所以this 无法访问受保护的方法.正如我们所看到的,当前的子类是该包中的一个类,这并不重要。 后门已关闭;)

    【讨论】:

    • Derived 是 Base 的子类。
    • @abson - 等一下,理解你的问题,仍在编辑并试图解释;)
    • 我发现逻辑被破坏了,为什么在具有包私有访问权限的基类的情况下,即使它们位于不同的包中,它也可以为其子级提供受保护的方法级访问。不明白为什么在这种情况下类也不应该被标记为受保护的(就像抽象,其中 min 1 抽象方法强制类被标记为抽象),或者至少是公共的以避免混淆。一般规则是首先是类级别的访问权限,然后是成员级别的访问权限。
    【解决方案2】:

    http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.6

    class C
        protected member;
    
    // in a different package
    
    class S extends C 
    
        obj.member; // only allowed if type of obj is S or subclass of S
    

    动机大概如下。如果obj 是S,则S 类对其内部有足够的了解,它有权操纵其成员,并且可以安全地做到这一点。

    如果obj 不是S,它可能是C 的另一个子类S2,S 不知道。 S2 可能在编写S 时还没有出生。对于S 来操作S2 的受保护内部结构是非常危险的。如果允许这样做,从S2 的角度来看,它不知道谁会篡改其受保护的内部结构以及如何篡改,这使得S2 的工作很难推理自己的状态。

    现在如果obj 是D 和D extends S,那么S 访问obj.member 是否危险?并不真地。 S 如何使用member 是S 及其所有子类(包括D)的共享知识。 S作为超类有定义行为的权利,D作为子类有接受和遵从的义务。

    为了更容易理解,该规则实际上应该被简化为要求obj 的(静态)类型恰好是S。毕竟,子类D 出现在S 中是非常不寻常和不合适的。即使发生这种情况,obj 的静态类型是D,我们的简化规则可以通过向上转换轻松处理:((S)obj).member

    【讨论】:

    • 嘿,我有一个好奇心。为什么obj的类型不能是'C'?答案可能很简单,但我无法得到它。请解释!谢谢
    • @ShashankAgarwal 你的问题得到答案了吗?
    【解决方案3】:

    受保护的访问有一些特殊规则,详见Java Language Specification:

    对象的受保护成员或构造函数可以从包外部访问,只有负责实现该对象的代码才能在该包中对其进行声明。

    【讨论】:

      【解决方案4】:

      首先想到的是你可以在任何软件中使用protectedObject,但只有不同的包非子类不能从其他类访问受保护的成员。这意味着您不能直接使用它。首先你得到那个 obj 然后使用。

          package Demos;
      
          public class AB
          {
              public    int a = 14;
              protected int b = 13;   
          }
      

      我们还有另一个类

      package Example;
      
      import Demos.AB;
      
      public class Ex1 extends AB
      {
          public static void main(String[] args)
          {
              AB obj = new AB();          // obj of AB                OR
                                          // AB obj = new Ex1(); object of Ex1 but referance of AB
                                          // cant use protacted member
      
              System.out.println(obj.a);
              System.out.println(obj.b);  //You can't use 
      
      
              Ex1 obj1 = new Ex1();       // you have to make obj of sub-class referance of Ex1
              System.out.println(obj1.a);
              System.out.println(obj1.b);  // Now You can use
          }
      }
      

      在这件事上,你必须扩展受保护成员的类,然后使用你不能直接使用 is。

      【讨论】:

        【解决方案5】:
        new Base().display();
        

        它创建一个 Base 对象,然后尝试调用它的 display()。
        显然它不会起作用,因为 Base 上的 display() 是受保护的。

        【讨论】:

        • 但是我从一个扩展它的类中调用它,所以它应该可以正常工作不是吗?
        • @abson: super.display() 很好。但在示例中,它创建了一个新对象,然后通过它调用。因此,除非它们在同一个包中,否则它不会起作用。
        【解决方案6】:

        这是预期的行为。 protected 表示继承的类和相同的包类可以看到该方法。所以,这就是你所看到的。

        【讨论】:

          【解决方案7】:

          这可能是对您问题的直接回答,但我认为您没有理由致电 new Base().display();。也许您在super.display(); 中的意思。

          在这种情况下,你实际上是在使用继承的方法,但仅仅因为你继承了一个类,并不意味着你访问了类受保护的方法(根据定义,仅对超类可见)。

          不同之处在于您尝试从您继承的类的实例访问受保护的方法(您的示例)。在我的示例中,您可以通过继承访问受保护的方法。

          总结:可以通过继承上下文访问方法。

          为什么?

          它让程序员可以灵活地决定哪些功能只能由直系后代使用或扩展。

          【讨论】:

            【解决方案8】:

            对象的受保护成员或构造函数只能由负责实现该对象的代码从声明它的包外部访问。

            【讨论】:

              【解决方案9】:

              display 不是 Base 中的静态方法。所以,你必须先创建一个 Base 的实例,然后调用 display。

              Base base = new Base();
              base.display();
              

              【讨论】:

              • 基础基础 =new Base();基地.显示;等同于 new Base().display();
              • 这是 OP 的相同代码。(-1)
              • 是的,你是对的!这是一个疏忽!
              猜你喜欢
              • 2013-03-14
              • 1970-01-01
              • 1970-01-01
              • 2016-01-07
              • 2014-05-21
              • 2016-10-01
              • 2012-05-26
              • 2012-11-20
              • 2013-02-03
              相关资源
              最近更新 更多