Java访问不同包中子类中的受保护成员,使用父类型的对象引用

时间:2015-08-13 18:17:50

标签: java inheritance polymorphism protected

我在两个单独的文件中有以下代码。

currentClientConnections

分配给package animal; public class Frog { protected void ribbit() { System.out.println("In Frog class!"); } } package other; import animal.*; public class Tadpole extends Frog { protected void ribbit() { System.out.println("In Tadpole class!"); } public static void main(String[] args) { Tadpole t = new Tadpole(); t.ribbit(); Frog f = new Tadpole(); f.ribbit(); // Does not compile } } 类型的第一个Tadpole对象显然编译得很好,而对Tadpole的调用将是ribbit()的{​​{1}}实现。创建并分配给Tadpole引用的第二个ribbit()对象。但是,对Tadpole的调用会导致编译器错误。

我知道如果你在子类中创建一个子类对象并分配给子类包之外的超类引用并尝试调用超类方法,则不允许这样做。但在这种情况下,不应该多态性使对象引用“f”调用Frog的{​​{1}}方法,因为分配了ribbit()个对象?为什么这会导致编译器错误,为什么不允许这样做?

6 个答案:

答案 0 :(得分:3)

这与访问protected班级成员的规则有关。有关详细信息,请参阅Java语言规范中的this section,具体如下:

  

设C为声明protected成员的类。只允许在C的子类S的主体内访问。

     

此外,如果 Id 表示实例字段或实例方法,则:

     
      
  • 如果访问是通过限定名称Q.Id或方法引用表达式Q :: Id(第15.13节),其中Q是ExpressionName,那么当且仅当类型为表达式Q是S或S的子类。

  •   
  • 如果访问是通过字段访问表达式E.Id,或方法调用表达式E.Id(...),或方法引用表达式E :: Id,其中E是主表达式(第15.8节),当且仅当E的类型为S或S的子类时才允许访问。

  •   

因此,在Frog的子类体内,如果x.ribbit()x子类,则只能访问Frog { {1}}无法声明为x)。

Frog成员存在此限制,因为否则,请假设protected具有受保护的Frog字段:

int

然后我们可以在public class Frog { protected int a = 1; ... } 的子类中定义public方法:

Frog

然后任何其他(不相关的)类都可以通过将public class TadPole extends Frog { public int revealFieldValueOfParent(Frog frog) { return frog.a; // imagine this was OK } } 传递给子类的方法来访问该字段:

Frog

修改

此编译器错误与多态无关。与对象的实际类型相关的多态性是运行时方面,编译器不会尝试在运行时认为变量public class SomeOtherClass { public static void main(String[] args) { TadPole tadpole = new TadPole(); Frog frog = new Frog(); int revealedValue = tadpole.revealFieldValueOfParent(frog); // print revealedValue } } 实际上是指f还是Frog }。所有编译器在这里都在强制执行Tadpole修饰符的规则,仅此而已。

编辑2:

根据以下评论,protected方法实际上显示 revealFieldValueOfParent(Frog frog)的值,如果我们将其更改为protected,但您也可以与私人成员一起做这个揭示技巧(即类似于getter方法)。知道它正在做什么,真正成为子类的责任。

答案 1 :(得分:1)

只要子类被声明为子类的类型而不是超类,

protected就会限制对Classpackage或子类的访问。

e.g。如果FrogTadpole位于不同的packagesFrog f = new Tadpole();如果您想要访问Frog的{​​{1}}方法,则无效ribbit {1}}

答案 2 :(得分:1)

为了简单理解,方法覆盖是运行时功能。这是在运行时获得的,编译器在编译期间不关心这一点。所以你的代码必须符合编译器。所以你的编译失败了,因为在编译期间无法从其他包中访问该方法(尽管它在运行时可以继承Frog类时可用)。

答案 3 :(得分:0)

受保护的访问修饰符 - 在超类中声明受保护的变量,方法和构造函数只能由其他包中的子类或受保护成员的包中的任何类访问。类。

答案 4 :(得分:0)

当你试图从Frog对象调用方法时,在编译时它只查找Frog类方法原型并且它被声明为protected,这在Frog类之外是不可见的。 希望这可以帮助你

答案 5 :(得分:0)

感谢您的所有回复。根据一些回复,我想我已经弄清楚为什么这不能编译。我发布了一个单独的回复,以使其完全清楚,并将澄清哪些内容无法访问,因为我觉得许多回复只包含解释的片段。

Frog f = new Tadpole();
f.ribbit(); // does not compile

上面没有编译,因为虽然Tadpole对象是在Tadpole类中创建的,并且正在调用Tadpole的ribbit()方法,但是使用Frog对象引用调用它。这里我们有一个分配给超类引用的子类,并且由于多态性,Frog对象引用" f"将尝试调用蝌蚪的ribbit()方法。但是,因为ribbit()受到保护而Frog不是Tadpole的子类,所以Frog类型的对象引用无法访问Tadpole中定义的受保护方法。这就是代码无法编译的原因。

同样,这很令人困惑,因为Tadpole是Frog的子类,所有调用都是在子类Tadpole中进行的。值得注意的是,调用本身是使用对象引用进行的,并且#34; f"尝试从Tadpole和Frog访问受保护方法的Frog类型不是Tadpole的子类。