从不同包的另一个实例的子类调用受保护的方法

6
我想从提供受保护方法的类的子类中调用另一个实例的受保护方法。请参见以下示例:
public class Nano {

    protected void computeSize() {
    }

}

public class NanoContainer extends Nano {

    protected ArrayList<Nano> children;

}

public class SomeOtherNode extends NanoContainer {

    // {Nano} Overrides

    protected void computeSize() {
        for (Nano child: children) {
            child.computeSize();            // << computeSize() has protected access in nanolay.Nano
        }
    }

}

javac告诉我Nano中的computeSize()访问受保护。我不知道原因(我以为我已经在其他代码中这样做了)。我希望仍然保持该方法受保护,我该怎么办?

javac version "1.7.0_09"

编辑

我想提供一个简化版本,但我没有考虑到不同包中的类的问题。

nanolay.Node
nanolay.NanoContainer
nanogui.SomeOtherNode

1
您能否显示这些类所在的包? - Scorpion
啊,包..我没有考虑到那个。我想提供一个简化版本的代码。我已经编辑了问题。 - Niklas R
请问您能否在问题标题中添加包限定符,因为这似乎是相关的? - Miserable Variable
@MiserableVariable:这样可以吗?我还用“packages”标签替换了“instance-methods”。 - Niklas R
是的,这很好。顺便说一下,被接受的答案需要进行一些更正。 - Miserable Variable
2个回答

15
不知道原因是什么,但是JLS在6.6.2. Details on protected Access中确认了这一点(我强调):

一个对象的protected成员或构造函数只能被负责该对象实现的代码从声明它的包之外访问。

所以:
package P2;
public class P2 {
    protected void foo() {}
}

.........

package P2A;    
class P2A extends P2.P2 {
    void bar(P2.P2 other) {
        this.foo(); // OK
        other.foo();  // ERROR
    }

    void bar2(P2A other) { 
        other.foo(); //OK
    }
}   

在`P2A.bar`中,调用`this.foo()`是可访问的,因为`this`负责实现`P2`,但`other.foo()`是不可访问的,因为`other`可能不是`P2A`。另一方面,`bar2`有一个`P2A`,所以一切都很好。
现在,为什么如果它们都是同一个包就没问题,但如果它们是不同的包就有问题呢?这是什么原因?我不知道,想知道。

谢谢你的总结,我完全同意你的观点。这种行为对我来说似乎不合法。 - Niklas R
也许你可以问另一个关于理论基础的问题。这可能不适合在这个论坛上讨论,但是程序员喜欢这些类型的问题。 - Miserable Variable
1
为什么other必须是P2A?它不只是需要成为P2.P2来访问foo();吗?因为foo是在P2.P2中声明的。请澄清一下。 - amarnath harish
1
访问同一包外部的受保护成员或受保护方法时,不能使用父类对象,只能使用实现类对象来访问父类的受保护成员。 - user6091735
如果我写成这样会怎么样呢: P2 p = new P2A(); p.foo(); 虽然这也不被允许,但是我想知道原因是什么? - Chandan Gupta

8
您可以通过继承和覆盖的方式或者在同一个包内访问受保护的方法。我会补充一些细节。您可以在此处阅读详细信息:链接
这个例子是关于java中Object类中可用的protected clone()方法;您不能直接在任何对象上调用它(尽管所有对象都隐式地继承自Object类)。

但是我不能对超类的另一个实例进行子类化并调用方法,就像我上面所做的那样?(假设它们在不同的包中,因为当它们在同一个包中时它可以工作) - Niklas R
某othernode对象的一个实例可以访问受保护的computeSize方法,但不能访问某othernode的其他实例 - 因此不能在for循环中访问。 - Scorpion
@Scorpion,这似乎是错误的。如果它们都在同一个包中,则可以编译而无错误。 - Miserable Variable
无法调用clone,因为它在java.lang包中的Object类中是protected的,而此类不在该包中。 - Miserable Variable
如果所有类都在同一个包中,它将正确编译。克隆示例说明了这一点 - 不同包中的受保护方法无法被调用;因此,您需要在java.lang之外创建一个员工类,因此除非通过public修饰符公开它,否则无法调用此员工类对象上的克隆方法。 - Scorpion

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接