Java 为什么可以';t我的子类在';它在另一个包裹里?

Java 为什么可以';t我的子类在';它在另一个包裹里?,java,packages,access-modifiers,protected,Java,Packages,Access Modifiers,Protected,我在package数据库中有一个抽象类relation,在package数据库中有一个relation,在package数据库中有一个子类Join关系有一个名为msstructure的受保护成员 在连接中: public Join(final Relation relLeft, final Relation relRight) { super(); mRelLeft = relLeft; mRelRight = relRight;

我在package
数据库中有一个抽象类
relation
,在package
数据库中有一个relation
,在package
数据库中有一个子类
Join
<代码>关系
有一个名为
msstructure
的受保护成员

连接中

public Join(final Relation relLeft, final Relation relRight) {
        super();
        mRelLeft = relLeft;
        mRelRight = relRight;
        mStructure = new LinkedList<Header>();
        this.copyStructure(mRelLeft.mStructure);

        for (final Header header :mRelRight.mStructure) {
        if (!mStructure.contains(header)) {
            mStructure.add(header);
        }
    }
}

我得到以下错误:

字段Relation.msstructure不可见


如果我将这两个类放在同一个包中,这将非常有效。有人能解释这个问题吗?

如果
protected
,您的
Join
实例在包外的其他实例(
relRight
relLeft
)中无法访问
msstructure

编辑:

该表很好地解释了这种情况。我用
[]
s标记了你问题中的罪犯

Access Levels
Modifier    Class Package Subclass  World
public      Y     Y       Y         Y
protected   Y    [Y]      Y         N
no modifier Y     Y       N         N
private     Y     N       N         N

一个鲜为人知的警告:

6.6.2受保护访问的详细信息

函数的受保护成员或构造函数 对象可以从外部访问 在其中声明它的包 仅由负责 该对象的实现


它可以工作,但只有您的孩子尝试访问它自己的变量,而不是其他实例的变量(即使它属于同一继承树)

请参阅此示例代码以更好地理解它:

//in Parent.java
package parentpackage;
public class Parent {
    protected String parentVariable = "whatever";// define protected variable
}

// in Children.java
package childenpackage;
import parentpackage.Parent;

class Children extends Parent {
    Children(Parent withParent ){
        System.out.println( this.parentVariable );// works well.
        //System.out.print(withParent.parentVariable);// doesn't work
    } 
}
如果我们尝试使用
withParent.parentVariable
编译,我们得到:

Children.java:8: parentVariable has protected access in parentpackage.Parent
    System.out.print(withParent.parentVariable);

它是可访问的,但只能访问它自己的变量

问题是您正在访问其他受实例保护的成员

您可以应用多个解决方案,例如,如果可能,您可以在父类中声明以下两种方法:

protected void copyRelationStructure(Relation r) {
  this.copyStructure(r.mStructure);
}

protected void mergeRelationStructure(Relation r) {
  for (final Header header: r.mStructure) {
    if (!mStructure.contains(header)) {
      mStructure.add(header);
    }
  }
}
然后在childs代码中替换:

this.copyStructure(mRelLeft.mStructure);

for (final Header header :mRelRight.mStructure) {
  if (!mStructure.contains(header)) {
    mStructure.add(header);
  }
}
与:


这应该行得通。现在,Relation有责任提供方法,允许将其内部的操作传递给其子级。这一政策背后的原因可能是,除非孩子是同一软件包的一部分,否则他们不应该弄乱家长的内部结构,以限制不兼容。

Mmmhh您的第一个解释只是说,OP ask首先是“无法访问它”。你的编辑没有完全澄清问题。我认为我的第一个解释与你的解释基本相同。关于编辑,表格怎么没有澄清问题?OP描述了基于表所期望的行为——一个类的实例可以访问任何类的另一个实例的受保护成员,如果它们位于同一个包中。此外,类的实例可以访问在其父类中定义的受保护成员,即使父类位于另一个包中。您引用的表附带的文本明确说明了允许OP执行的操作—“受保护修饰符指定只能在其自己的包中访问该成员(与package private一样)以及另外一个包中它的类的子类。“也许我很高兴读错了。我想这可以归结为在本文中被认为是“子类”的内容。我发现§6.6.7中的示例在这里很有用。正式定义澄清了“负责实现”在§6.6.2.1中,合适的解决方案是定义受保护的访问器吗?同样的情况也会发生。更有趣的是,如果
Join
is-a
relationship
,如果是,为什么它们应该放在不同的包中。可能,使用中间对象来抽象结构并可以。我建议您移动我现在在同一个包中,只是为了避免陷入编码瘫痪。我相信你的第一句话会更准确一些,如果你说在子类中,你可以在子类的任何实例上访问该成员,或者在继承自子类的类的任何实例上访问该成员,但不能访问子类继承的类的任何实例lass继承自(见本规范第6.6.2.1节:)。因此,它可以在继承树的进一步派生成员中看到它,而不是在派生较少的成员中看到它。无可否认,这说起来有点过分。@TimGoodman我在6.6.2.1中没有看到任何区别。唯一接近这一点的是在其自身下的单个段落中使用“对象”而不是“类”。
protected void copyRelationStructure(Relation r) {
  this.copyStructure(r.mStructure);
}

protected void mergeRelationStructure(Relation r) {
  for (final Header header: r.mStructure) {
    if (!mStructure.contains(header)) {
      mStructure.add(header);
    }
  }
}
this.copyStructure(mRelLeft.mStructure);

for (final Header header :mRelRight.mStructure) {
  if (!mStructure.contains(header)) {
    mStructure.add(header);
  }
}
this.copyRelationStructure(mRelLeft);
this.mergeRelationStructure(mRelRight);