在Java中,在创建类和接口以及处理继承时,是否有明确的规则来确定何时使用每个访问修饰符,即默认的(包私有)、公共的、受保护的和私有的?


当前回答

我经常意识到,通过创造真实世界的类比,记住任何语言的基本概念都是可能的。下面是我在Java中理解访问修饰符的类比:

让我们假设你是一个大学的学生,你有一个朋友周末来拜访你。假设校园中央有一座大学创始人的大雕像。

当你把他带到校园时,你和你的朋友首先看到的就是这尊雕像。这意味着任何在校园里行走的人都可以在没有大学许可的情况下观看雕像。这使雕像成为公共的。接下来,你想带你的朋友去你的宿舍,但为此你需要将他登记为访客。这意味着他可以获得进入校园各个建筑的通行证(与你的通行证相同)。这将使他的门禁卡受到保护。你的朋友想登录校园WiFi,但没有任何凭据。他唯一可以上网的方式是你和他分享你的登录信息。(记住,每个上大学的学生都拥有这些登录凭据)。这将使您的登录凭据为NO MODIFIER。最后,你的朋友想看看你在网站上发布的学期进度报告。然而,每个学生都有自己的个人登录来访问校园网站的这一部分。这将使这些凭据成为PRIVATE。

希望这有帮助!

其他回答

平民的如果用public声明类成员,则可以从任何地方访问它受保护的如果用关键字protected声明类成员,则可以从相同的类成员、同一包内的外部类成员和继承的类成员访问该类成员。如果类成员受到保护,则不能从外部包类访问它,除非外部包类被继承,即扩展其他包超类。但是,受保护的类成员始终可用于相同的包类,无论是否继承了相同的包类别违约在Java中,默认值不是访问修饰符关键字。如果声明的类成员没有任何访问修饰符关键字,那么在这种情况下,它被视为默认成员。默认类成员始终可用于相同的包类成员。但即使外部类是与受保护成员不同的子类,外部包类成员也不能访问默认类成员私有的如果用关键字protected声明了类成员,那么在这种情况下,它只对相同的类成员可用

访问修饰符用于限制多个级别的访问。

公共:它基本上和您可以从任何类访问一样简单,无论它是否在同一个包中。

若要访问同一个包,可以直接访问,但若您在另一个包中,则可以创建类的对象。

默认值:它可以在同一个包中从任何一类包访问。

要访问,可以创建类的对象。但不能在包外访问此变量。

受保护:您可以访问同一包中的变量以及任何其他包中的子类。所以基本上它是默认+继承的行为。

要访问基类中定义的受保护字段,可以创建子类的对象。

私有:可以在同一类中访问。

在非静态方法中,由于该引用(也在构造函数中),您可以直接访问,但要在静态方法中访问,您需要创建类的对象。

Java中的访问说明符:java中有4个访问说明符,即private、packageprivate(默认)、protected和public,访问顺序依次递增。

私人:当您正在开发某个类,并且希望该类的成员不暴露在该类之外时,应该将其声明为私有。私有成员只能在定义了它们的类(即封闭类)中访问。私有成员可以在“this”引用上访问,也可以在包含这些成员的类的其他实例上访问,但只能在该类的定义内访问。

包专用(默认):除了下面描述的访问之外,此访问说明符还将提供专用访问说明符指定的访问。

当您开发某个包并因此开发其中的某个类(比如Class1)时,您可以使用默认(无需明确提及)访问说明符,将类中的成员暴露给(同一)包中的其他类。在这些其他类(在同一个包中)中,您可以访问Class1实例上的这些默认成员。此外,您还可以在Class1的子类中访问这些默认成员,例如Class2(在该引用上、Class1的实例上或Class2的实例上)。

基本上,在同一个包中,您可以直接访问类实例上的默认成员,也可以访问子类中的“this”引用。

受保护的:除了下面描述的访问之外,此访问说明符还将提供由包专用访问说明符指定的访问。

当您正在开发某个包,从而在其中开发某个类(例如Class1)时,如果您不希望在包外部(例如在包的消费者的包中,即使用您的API的客户机)访问Class1中的数据成员,则应在Class1中使用受保护的访问说明符,但您希望创建一个例外,并且仅当客户端编写扩展Class1的Class2类时才允许访问该成员。因此,一般来说,受保护的成员可以在派生类(即Class2)中的“this”引用上访问,也可以在Class2的显式实例上访问。

请注意:

您将无法访问中继承的Class1受保护成员如果您试图在Class1的显式实例上访问它,尽管它是遗传的。当您在相同/不同的包中编写另一个类Class3时如果扩展了Class2,则可以访问Class1中的受保护成员该引用以及Class3的显式实例。这将对于任何扩展的层次结构(即受保护的成员)均为true仍然可以在此引用或扩展实例上访问班注意,在Class3中,如果创建Class2的实例但您将无法从Class1访问受保护的成员它是遗传的。

所以,底线是,只有当来自此其他包的某个类、包含此受保护成员的扩展类以及受保护成员在扩展类的定义内通过“this”引用或扩展类的显式实例访问时,才能在其他包中访问受保护成员。

public:除了下面描述的访问之外,此访问说明符还将提供受保护访问说明符指定的访问。

当您正在开发某个包以及其中的某个类(比如Class1)时,如果您希望在其他包的某个类别中创建的Class1实例的其他包中可以访问Class1中的数据成员,则应使用Class1中数据成员的公共访问说明符。基本上,当您打算无条件地向世界公开数据成员时,应该使用此访问说明符。

(注意:我不是一个Java程序员,我是一个Perl程序员。Perl没有正式的保护措施,这也许就是为什么我如此理解这个问题的原因:)

私有的

就像你想的那样,只有声明它的类才能看到它。

包专用

它只能由声明它的包看到和使用。这是Java中的默认设置(有些人认为这是错误的)。

受保护的

包Private+可以由子类或包成员看到。

平民的

每个人都能看到。

出版

在我控制的代码之外可见。(虽然不是Java语法,但这对本次讨论很重要)。

C++定义了一个称为“朋友”的附加级别,你对它了解得越少越好。

你什么时候应该用什么?整个想法是封装以隐藏信息。您希望尽可能地向用户隐藏某些操作的细节。为什么?因为这样你以后就可以更改它们,而不会破坏任何人的代码。这使您可以优化、重构、重新设计和修复错误,而不用担心有人在使用您刚刚大修过的代码。

因此,经验法则是让事物尽可能地可见。从私密开始,只在需要时增加更多的可见性。只公开用户需要知道的信息,你公开的每一个细节都限制了你重新设计系统的能力。

如果您希望用户能够自定义行为,而不是将内部公开以便他们可以覆盖它们,那么通常最好将这些内容插入到对象中并将接口公开。这样他们就可以简单地插入一个新对象。例如,如果您正在编写一个CD播放器,并希望“go find info about this CD”位可定制,而不是将这些方法公开,那么您应该将所有这些功能放入其对象中,并仅将对象getter/setter公开。通过这种方式,吝啬于暴露自己的内心会鼓励良好的组合和关注的分离

我只坚持“私人”和“公共”。许多OO语言都有这一点。“受保护”可能很方便,但这是一个骗局。一旦一个接口超过了私有,它就超出了你的控制范围,你必须去查看其他人的代码才能找到用途。

这就是“发布”的概念所在。更改接口(重构它)需要找到使用它的所有代码并进行更改。如果接口是私有的,那么没问题。如果它受到保护,你必须找到所有的子类。如果它是公开的,你必须找到使用你的代码的所有代码。有时这是可能的,例如,如果您正在编写仅供内部使用的公司代码,那么接口是否公开无关紧要。您可以从公司存储库中获取所有代码。但是,如果一个接口被“发布”,如果有代码在您的控制之外使用它,那么您将被罚款。您必须支持该接口,否则可能会破坏代码。即使是受保护的接口也可以被认为是已发布的(这就是为什么我不关心受保护的)。

许多语言发现公共/受保护/私有的等级性质过于局限,不符合现实。为此,有一种特质类的概念,但这是另一种表现。

当你想到访问修饰符时,你可以这样想(适用于变量和方法):

public-->可从任何位置访问private-->只能在声明它的同一类中访问

现在,当涉及到默认和受保护时,就会出现混乱

默认-->不存在访问修饰符关键字。这意味着它严格在类的包中可用。在该包之外,任何地方都无法访问。

protected-->略低于默认值,并且除了相同的包类之外,它可以由声明的包之外的子类访问。