简体   繁体   English

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

[英]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()的调用将是Tadpoleribbit()实现。 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”调用Tadpoleribbit()方法,因为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的子类体内,如果xFrog子类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. 只要子类被声明为子类的类型而不是超Classprotected限制对Classpackage或子类的访问。

eg if Frog and Tadpole are in different packages , Frog f = new Tadpole(); 例如,如果FrogTadpole在不同的packagesFrog f = new Tadpole(); does not work if you want to access Frog 's ribbit method, but Tadpole f = new Tadpole(); 如果你想访问Frogribbit方法,那就行不通了,但是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.

相关问题 子类访问中的受保护方法,它位于不同的包中 - Protected methods in subclass access which is in different package Java:对超类对象上的子类的受保护访问限制 - Java : Protected access restriction for subclass on superclass object 是否可以从 Java 中的“相同包非子类”访问受保护的成员? - Is protected member accessible from “same package non-subclass” in Java? Java - 为什么另一个 package 中的子级无法通过父级引用访问父级的受保护方法? - Java - Why Child in another package cannot access parent's protected method through parent reference? Java:无法访问扩展子类中超类的受保护成员 - Java: cannot access a protected member of the superclass in the extending subclass 使用java中的父引用类型访问变量 - Access a variable using parent reference type in java 受保护的为什么不能在不同的包子类中访问? - protected can't access in different package subclass why? 访问父级子类中静态类的受保护成员 - Accessing protected member of static class in subclass of the parent 类无法使用来自不同包的反射来访问其自己的受保护的成员变量 - Class can't access its own protected member variable using reflection from different package 为什么不同包中的子类无法通过超类实例访问其在另一个包中的超类的受保护字段? - Why a subclass in a different package is unable to access the protected fields of its superclass in another package through superclass instance?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM