Java中的protected访问修饰符

11

我有些难以理解Java中protected访问修饰符(或其背后的设计)。我认为它表示包访问和通过继承包含抽象成员的类的对象进行访问。

我编写了以下示例代码。我发现如果取消注释,那么注释掉的行会产生编译错误。为什么我可以通过Second对象在Second中访问pro,但不能通过First对象在Second中访问?

package first;

public class First {

    protected void pro(){
        System.out.println("Can see protected method");
    }

}

package first;

public class InFirst {


    public static void main(String[] args){
        First fst = new First();
        fst.pro();
    }

}

package second;

import first.First;

public class Second extends First {

    public static void main(String[] args){

        First fst = new First();

//      fst.pro();

        Second sec = new Second();
        sec.pro();

    }
}

2
你可能需要阅读控制类成员的访问权限以获取更多细节。 - MadProgrammer
好的观察。这通常会让很多开发人员感到困惑。请参见下面的图表,或许有所帮助。 - Ryan
@MadProgrammer:谢谢,我已经阅读了这篇文章。我对他们在protected修饰符中使用“由另一个包中其类的子类”这个短语感到困惑。如上所示,我可以通过Second对象sec访问Second中的pro,但不能通过First对象fst访问。 - B M
@BM - 我认为你在子类访问父类受保护成员时缺失的重要细节是,访问必须发生在子类“实现”的上下文中(规范引用的是body,差异不大)。任何类的主方法被视为其实现的一部分,这就是为什么您会收到错误提示的原因。 - Perception
这是一个简单的“备忘单”,解释了protected和其他访问修饰符。链接 - aioobe
显示剩余4条评论
4个回答

17

网页 @MadProgrammer 链接给出了一个不错的解释:

“受保护的修饰符指定了成员只能在其自己的包中访问(与包私有相同),并且还可以被另一个包中其类的子类访问。”

这意味着受保护的成员必须通过定义该成员的类或该类的子类直接访问,同时也必须在适当的包内。这并不一定意味着您可以通过在该类的子类中创建的实例来访问受保护的成员。重点在于涉及的包。

以下是示例:

package first; // Current package

First fst = new First(); // from package first and does not extend anything
fst.pro();

尝试从哪个包访问该成员?第一个

包含该成员的(子)类或其继承该成员的父类是否在同一个包中定义?是的,Firstpackage first中定义,因此可以从package first中的First访问该protected成员。

package second; // Current package

First fst = new First(); // from package first and does not extend anything
fst.pro();

尝试从哪个包中访问该成员变量?是来自second包。

包含该成员变量的(子)类或其从中继承成员变量的父类是否在同一包中定义?否,First定义在package first中,因此protected使得该成员变量无法被package second中的First所访问。

package second; // Current package

Second sec = new Second(); // from package second and extends First from package first
sec.pro();

试图从哪个包中访问该成员? second

包含该成员的(子)类或其从中继承该成员的父类是否在同一个包中定义?是的,Secondpackage second 中定义,从 First 继承该成员,因此在 package second 中可以从 Second 访问受保护的成员。

更多例子以便说明:

package first; // Current package

Second sec = new Second(); // from package second and extends First from package first
sec.pro();

尝试从哪个包中访问该成员? 第一个

包含该成员的(子)类或者继承该成员的父类是否在同一个包中定义?是的,Second 继承自定义在 package first 中的 First,因此可以从 package first 中的 Second 访问 protected 成员。

package first; // Current package

Third third = new Third(); // from package third and extends Second from package second,
                           // which extends First from package first
third.pro();

尝试从哪个包中访问问题的成员?是来自第一个包吗?

包含该成员的(子)类或其继承该成员的父类是否在同一个包中定义? 是的,Third 继承了 Second 的成员,而 Second 又从定义该成员的 First 继承而来 (package first),因此 protected 成员可以在 package first 中通过 Third 访问。


感谢您清晰的解释。我还找到了这个扩展图表,它涵盖了所有情况,其中一些情况在上面的链接中没有涵盖。http://bmanolov.free.fr/javaprotection.php - B M

2

protected vs. default这里有一张图表展示了访问级别。你的代码属于图表中Convertible中的R(Reference)情况。也就是说,在另一个包中的子类中引用是不被允许访问的。


谢谢提供这个图表。但是我无法阅读上面的文字。是否有更清晰的链接可用? - B M
以下是链接:http://www.programcreek.com/2009/02/diagram-to-illustrate-protected-and-default-difference/。 - Ryan

1

Java中的受保护成员

同一包内 - (它的行为类似于默认)

在同一类、其子类以及非子类中都可以访问它(它的行为类似于默认)。您甚至可以使用父级或子级引用来访问受保护的成员。

包外 -

只有它的子类才能访问它,最重要的一点是所使用的引用必须是相同的子类。


0

protected的意思是在同一个包中的其他类可见。由于Second在不同的包'second.Second'中,因此无法访问first中的.pro()。

如果您将Second创建在'first'包名下,则可以正常工作。


1
这并不是 protected 的全部含义。它还意味着可以从子类访问。这就是为什么我可以从 Second 中的一个 Second 对象访问 pro。 - B M
查看Syborg上面说的内容。“子类和同一包”。 - timzilla

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