[英]Java access to protected member in subclass in different package, using object reference of parent type
I have the following code in two separate files. 我在两个单独的文件中有以下代码。
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
}
}
The first Tadpole
object assigned to Tadpole
type obviously compiles fine and the call to ribbit()
will be to the Tadpole
's ribbit()
implementation. 分配给
Tadpole
类型的第一个Tadpole
对象显然编译得很好,对ribbit()
的调用将是Tadpole
的ribbit()
实现。 The second Tadpole
object that is created and assigned to a Frog
reference. 创建并分配给
Frog
参考的第二个Tadpole
对象。 However, the call to ribbit()
results in a compiler error. 但是,对
ribbit()
的调用会导致编译器错误。
I know that if you create a subclass object in the subclass and assign to a superclass reference that is outside of the subclass's package and try to call a superclass method, this is not allowed. 我知道如果你在子类中创建一个子类对象并分配给子类的包之外的超类引用并尝试调用超类方法,则不允许这样做。 But in this case, shouldn't polymorphism make the object reference "f" call the
Tadpole
's ribbit()
method since a Tadpole
object was assigned to it? 但是在这种情况下,不应该多态性使对象引用“f”调用
Tadpole
的ribbit()
方法,因为Tadpole
对象被分配给它? Why does this cause a compiler error and why is this is not allowed? 为什么这会导致编译器错误,为什么不允许这样做?
This is related to the rules about access to protected
class members. 这与有关访问
protected
类成员的规则有关。 See this section from the Java Language Specification on details, specifically: 有关详细信息,请参阅Java语言规范中的此部分 ,具体如下:
Let C be the class in which a
protected
member is declared.设C是声明
protected
成员的类。 Access is permitted only within the body of a subclass S of C.仅允许在C的子类S的主体内访问。
In addition, if Id denotes an instance field or instance method, then:
此外,如果Id表示实例字段或实例方法,则:
If the access is by a qualified name Q.Id or a method reference expression Q :: Id (§15.13), where Q is an ExpressionName, then the access is permitted if and only if the type of the expression Q is S or a subclass of S.
如果访问是通过限定名称Q.Id或方法引用表达式Q :: Id(第15.13节),其中Q是ExpressionName,则当且仅当表达式Q的类型是S或a时才允许访问S的子类
If the access is by a field access expression E.Id, or a method invocation expression E.Id(...), or a method reference expression E :: Id, where E is a Primary expression (§15.8), then the access is permitted if and only if the type of E is S or a subclass of S .
如果访问是通过字段访问表达式E.Id,或方法调用表达式E.Id(...),或方法引用表达式E :: Id,其中E是主表达式(第15.8节),那么当且仅当E的类型是S或S的子类时才允许访问 。
So within the body of a subclass of Frog
, you can only access x.ribbit()
if x
is a subclass of Frog
( x
cannot be declared a Frog
). 因此,在
Frog
的子类体内,如果x
是Frog
的子类 ( x
不能被声明为Frog
),则只能访问x.ribbit()
)。
This restriction exists on protected
members, because otherwise, imagine that Frog
has a protected int
field: 这种限制存在于
protected
成员上,因为否则,想象Frog
有一个受保护的int
字段:
public class Frog {
protected int a = 1;
...
}
Then one would be able to define a public
method in the subclass of Frog
: 然后就可以在
Frog
的子类中定义一个public
方法:
public class TadPole extends Frog {
public int revealFieldValueOfParent(Frog frog) {
return frog.a; // imagine this was OK
}
}
Then any other (unrelated) class would be able to access the field by passing a Frog
to the method of the subclass: 然后任何其他(无关)类将能够通过将
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
}
}
EDIT: 编辑:
This compiler error has nothing to do with polymorphism. 此编译器错误与多态无关。 Polymorphism, as related to the actual type of the object, is a runtime aspect and the compiler does not try to think whether at runtime the variable
f
actually refers to a Frog
or to a Tadpole
. 与对象的实际类型相关的多态性是运行时方面,并且编译器不会尝试在运行时认为变量
f
实际上是指Frog
还是Tadpole
。 All the compiler is doing here is enforcing the rules of the protected
modifier, nothing more. 所有编译器在这里执行的是强制执行
protected
修饰符的规则,仅此而已。
EDIT 2: 编辑2:
Based on the comments below, the revealFieldValueOfParent(Frog frog)
method would actually reveal the value of the protected
if we change it to revealFieldValue(TadPole frog)
, but you can also do that revealing trick with private members (ie similar to a getter method). 根据下面的评论,如果我们将其更改为
revealFieldValue(TadPole frog)
,那么revealFieldValueOfParent(Frog frog)
方法实际上会揭示 protected
的值,但您也可以使用私有成员(即类似于getter方法)进行揭示技巧)。 It would really become the responsibility of the subclass to know what it's doing. 它应该真正成为子类的责任,知道它在做什么。
protected
limits access to Class
, package
, or subclass as long as the subclass is declared as type of subclass and not the superclass. 只要子类被声明为子类的类型而不是超
Class
, protected
限制对Class
, package
或子类的访问。
eg if Frog
and Tadpole
are in different packages
, Frog f = new Tadpole();
例如,如果
Frog
和Tadpole
在不同的packages
, Frog f = new Tadpole();
does not work if you want to access Frog
's ribbit
method, but Tadpole f = new Tadpole();
如果你想访问
Frog
的ribbit
方法,那就行不通了,但是Tadpole f = new Tadpole();
does 不
Just for simple understanding, method overriding is runtime feature . 只是为了简单理解,方法覆盖是运行时功能。 This is obtained in run time and compiler do not care about this during compilation.
这是在运行时获得的,编译器在编译期间不关心这一点。 So your code has to be compiler compliance .
所以你的代码必须符合编译器。 So your compilation fails because the method is not accessible from other package during compilation ( despite the fact that it would be available during run time as it inherits the Frog class).
因此编译失败是因为在编译期间无法从其他包访问该方法(尽管它在运行时可以继承,因为它继承了Frog类)。
受保护的访问修饰符 - 在超类中声明受保护的变量,方法和构造函数只能由其他包中的子类或受保护成员类的包中的任何类访问。
When you are trying to call method from Frog object, at compile time it looks only for Frog class method prototype and it is declared as protected which is not visible outside Frog class. 当你试图从Frog对象调用方法时,在编译时它只查找Frog类方法原型并且它被声明为protected,这在Frog类之外是不可见的。 Hope this helps you
希望这对你有所帮助
Thank you for all of your responses. 感谢您的所有回复。 Based on some of the responses, I think I've figured out why this does not compile.
根据一些回复,我想我已经弄清楚为什么这不会编译。 I'm posting a separate response to make it completely clear and will clarify which things don't have access with respect to what since I felt that many of the responses only contained snippets of the explanation.
我发布了一个单独的回复,以使其完全清楚,并将澄清哪些内容无法访问,因为我觉得许多回复只包含解释的片段。
Frog f = new Tadpole();
f.ribbit(); // does not compile
The above does not compile because although the Tadpole object is created in the Tadpole class itself and is calling Tadpole's ribbit() method, it is called using a Frog object reference. 上面的代码不能编译,因为虽然Tadpole对象是在Tadpole类中创建的,并且正在调用Tadpole的ribbit()方法,但是使用Frog对象引用调用它。 Here we have a subclass that is assigned to a superclass reference and because of polymorphism, the Frog object reference "f" will attempt to call Tadpole's ribbit() method.
这里我们有一个分配给超类引用的子类,由于多态性,Frog对象引用“f”将尝试调用Tadpole的ribbit()方法。 However, because ribbit() is protected and Frog is NOT a subclass of Tadpole, an object reference of type Frog cannot access a protected method defined in Tadpole.
但是, 因为ribbit()受到保护而Frog不是Tadpole的子类,所以Frog类型的对象引用无法访问Tadpole中定义的受保护方法。 This is why the code does not compile.
这就是代码无法编译的原因。
Again, this is confusing because Tadpole is a subclass of Frog and all calls are being made in the subclass Tadpole. 再次,这是令人困惑的,因为Tadpole是Frog的子类,所有调用都是在子类Tadpole中进行的。 The thing to note though is that the call itself is being made using an object reference "f" which is of type Frog that is attempting to access a protected method from Tadpole and Frog is NOT a subclass of Tadpole.
需要注意的是,调用本身是使用对象引用“f”进行的,它是Frog类型,试图从Tadpole访问受保护的方法,而Frog不是Tadpole的子类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.