【问题标题】:Can't access protected inner class while inheriting继承时无法访问受保护的内部类
【发布时间】:2009-09-28 15:34:13
【问题描述】:

阅读“Thinking in Java”后,我陷入了内部类章节的 ex:6 中。


练习 6:(2) 在自己的包中创建一个包含至少一种方法的接口。创建一个 类在一个单独的包中。添加实现接口的受保护内部类。在一个 第三个包,从你的类继承,并在一个方法中,返回一个对象 受保护的内部类,在返回期间向上转换到接口。


这是我的代码:

IOne.java

界面

package intfpack;
public interface IOne{
        void    f();
}

COne.java

具有实现接口的受保护内部类的类

package classpack;
import intfpack.*;
public class COne{
        protected class Inner implements IOne{
                public void f(){System.out.println("Inner class of COne");}
        } 
}

CTwo.java

从具有受保护内部类的类继承

package thirdpack;
import classpack.*;
import intfpack.*;

public class CTwo extends COne{
        public IOne getInner(){
                IOne io = new Inner(); 
                return io;
        }
        public static void main(String[] args){
                CTwo ct = new CTwo();
                ct.getInner();
        }
}

编译器接着说:

javac CTwo.java
CTwo.java:9: Inner() has protected access in classpack.COne.Inner
                IOne io = new Inner(); 
                          ^
1 error

但是这本书说我可以在派生类中访问受保护的内部类。哪里出错了?

【问题讨论】:

    标签: java inner-classes


    【解决方案1】:

    错误消息是抱怨构造函数受到保护,而不是类。但是您没有在发布的代码中明确定义构造函数。在这种情况下,according to the JLS,默认构造函数将受到保护(与类相同)。

    【讨论】:

    • 这是 Dan Dayer 链接的准确解释:Inner 的构造函数受到保护。但是,构造函数相对于 Inner 是受保护的,而 Inner 相对于 COne 是受保护的。因此,在 CTwo 中可以访问 Inner,因为它是 COne 的子类。 Inner 的构造函数在 CTwo 中不可访问,因为 CTwo 类不是 Inner 的子类!因此,即使 Inner 可以访问,它的默认构造函数也不是。
    【解决方案2】:

    您需要为Inner class 定义一个public 构造函数:

    public class COne {
    
        protected class Inner implements IOne{
    
            public Inner() { }
    
            public void f(){System.out.println("Inner class of COne");}
        }
    }
    

    【讨论】:

      【解决方案3】:

      这很清楚。 但这里有一件非常奇怪的事情。

      According to the JLS 如果 CTwo 扩展了 COne.Inner 它应该访问 Inner 的受保护构造函数,但实际上它不会... 见下文。

      package p1;
      public class COne {
          public static class Inner {
              protected Inner() {}
          }
      }
      
      package p2;
      public class CTwo extends COne.Inner {
          public void getIface() {
              new COne.Inner();
              // Compile time error anyway with the same complains:
              // "Inner() has protected access in p1.COne.Inner"
              // ...unlike my expectations...
          }
      }  
      

      【讨论】:

      • 您将无法以这种方式在 CTwo 中创建 COne.Inner 的实例。使 COne.Inner 的构造函数受保护有两件事:1) 它将 COne.Inner 的创建限制为包 p1 中的其他类 2) 它允许继承者调用该构造函数作为其构造的一部分。您的示例试图在另一个包中创建 COne.Inner() 的新实例,并且仅仅因为您在从 COne.Inner 继承的类中执行此操作不会使构造函数可访问。但是,当您创建 CTwo 的实例时,将调用您的构造函数。
      【解决方案4】:

      问题不在于 Inner 类,而在于继承。

      让我们做一些实验。

      第一个 InnerOuter 类都具有彼此的完全访问权限。所以下面的代码运行良好。

      package com.ciaoshen.packA;
      
      public class Outer {
              protected class Inner {
                  public void foo() { System.out.println("Hello Ronald!"); }
              }
              protected Inner inner() {
                  return new Inner();
              }
              public static void main(String[] args) {
                  new Outer().inner().foo(); // Output: Hello Ronald!
              }
      }
      

      现在在另一个包中,DerivedOuter 派生自 OuterDerivedOuter 调用继承自 Outerclass 的 inner()method。它仍然有效!

      package com.ciaoshen.packB;
      
      class DerivedOuter extends Outer {
          public static void main(String[] args) {
              new DerivedOuter().inner().foo(); // Output: Hello Ronald!
          }
      }
      

      但是当我在DerivedOuter 类中重写inner() 方法时,会出现同样的错误!

      package com.ciaoshen.packB;
      
      class DerivedOuter extends Outer {
          @Override
          public Inner inner() { // this is not the inner() of Outer class. BOOM!
              return new Inner();
          }
          public static void main(String[] args) {
              new DerivedOuter().inner().foo(); // ERROR: Outer.Inner() has protected access in Outer.Inner
          }
      }
      

      结论,受保护的内部构造函数只能在原始Outer 类范围内访问。任何其他方法(例如:您的 getInner() 方法)都无法访问受保护的 Inner 构造函数。

      关键是当DerivedOuterOuter继承时,你可以想象DerivedClass是一个Outer,它里面包含一个Inner类作为他的成员。但实际上,DerivedOuter 无法直接访问Inner 类,而只能使用他的超类Outer

      【讨论】:

        猜你喜欢
        • 2011-05-24
        • 1970-01-01
        • 2019-05-16
        • 1970-01-01
        • 2014-04-21
        • 1970-01-01
        • 2020-09-14
        • 2023-03-23
        • 2017-09-26
        相关资源
        最近更新 更多