继承时无法访问受保护的内部类

Posted

技术标签:

【中文标题】继承时无法访问受保护的内部类【英文标题】: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

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

【问题讨论】:

【参考方案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

【讨论】:

以上是关于继承时无法访问受保护的内部类的主要内容,如果未能解决你的问题,请参考以下文章

无法访问受保护的成员[重复]

无法访问派生类中基类的受保护成员

C#:基类中的受保护方法;无法使用来自另一个类的派生类对象进行访问[重复]

策略继承和不可访问的受保护成员

在派生类中无法访问受保护的成员

Java:从内部类访问受保护的字段