Java 中的 public、protected、package-private 和 private 之间有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/215497/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 11:30:26  来源:igfitidea点击:

What is the difference between public, protected, package-private and private in Java?

javaprivatepublicprotectedaccess-modifiers

提问by intrepion

In Java, are there clear rules on when to use each of access modifiers, namely the default (package private), public, protectedand private, while making classand interfaceand dealing with inheritance?

在Java中,有没有关于何时使用每个访问修饰符,即默认(包专用),明确的规则publicprotected并且private,同时使classinterface和处理继承?

采纳答案by David Segonds

The official tutorialmay be of some use to you.

官方教程可能对你有用。

______________________________________________________________
|           │ Class │ Package │ Subclass │ Subclass │ World  |
|           │       │         │(same pkg)│(diff pkg)│        |
|───────────┼───────┼─────────┼──────────┼──────────┼────────|
|public     │   +   │    +    │    +     │     +    │   +    | 
|───────────┼───────┼─────────┼──────────┼──────────┼────────|
|protected  │   +   │    +    │    +     │     +    │        | 
|───────────┼───────┼─────────┼──────────┼──────────┼────────|
|no modifier│   +   │    +    │    +     │          │        | 
|───────────┼───────┼─────────┼──────────┼──────────┼────────|
|private    │   +   │         │          │          │        |
|___________|_______|_________|__________|__________|________|
 + : accessible         blank : not accessible

回答by John Nilsson

Easy rule. Start with declaring everything private. And then progress towards the public as the needs arise and design warrants it.

容易的规则。从声明一切私有开始。然后随着需求的出现和设计的需要,向公众迈进。

When exposing members ask yourself if you are exposing representation choices or abstraction choices. The first is something you want to avoid as it will introduce too many dependencies on the actual representation rather than on its observable behavior.

在公开成员时,问问自己是公开表示选择还是抽象选择。第一个是您想要避免的,因为它会引入对实际表示而不是其可观察行为的太多依赖。

As a general rule I try to avoid overriding method implementations by subclassing; it's too easy to screw up the logic. Declare abstract protected methods if you intend for it to be overridden.

作为一般规则,我尽量避免通过子类化来覆盖方法实现;逻辑太容易搞砸了。如果您打算覆盖它,请声明抽象受保护的方法。

Also, use the @Override annotation when overriding to keep things from breaking when you refactor.

此外,在重写时使用 @Override 注释以防止重构时破坏。

回答by Joe Phillips

The difference can be found in the links already provided but which one to use usually comes down to the "Principle of Least Knowledge". Only allow the least visibility that is needed.

差异可以在已经提供的链接中找到,但使用哪个链接通常归结为“最少知识原则”。只允许所需的最低可见性。

回答by Schwern

(Caveat: I am not a Java programmer, I am a Perl programmer. Perl has no formal protections which is perhaps why I understand the problem so well :) )

(警告:我不是 Java 程序员,我是 Perl 程序员。Perl 没有正式的保护措施,这也许是我对问题如此了解的原因:))

Private

私人的

Like you'd think, only the classin which it is declared can see it.

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

Package Private

包私人

Can only be seen and used by the packagein which it was declared. This is the default in Java (which some see as a mistake).

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

Protected

受保护

Package Private + can be seen by subclasses or package member.

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

Public

民众

Everyone can see it.

每个人都可以看到它。

Published

已发表

Visible outside the code I control. (While not Java syntax, it is important for this discussion).

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

C++ defines an additional level called "friend" and the less you know about that the better.

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

When should you use what? The whole idea is encapsulation to hide information. As much as possible you want to hide the detail of how something is done from your users. Why? Because then you can change them later and not break anybody's code. This lets you optimize, refactor, redesign and fix bugs without worry that someone was using that code you just overhauled.

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

So, rule of thumb is to make things only as visible as they have to be. Start with private and only add more visibility as needed. Only make public that which is absolutely necessary for the user to know, every detail you make public cramps your ability to redesign the system.

因此,经验法则是使事物仅在必须可见的情况下才可见。从私有开始,仅根据需要添加更多可见性。只公开那些绝对需要用户知道的信息,你公开的每一个细节都会限制你重新设计系统的能力。

If you want users to be able to customize behaviors, rather than making internals public so they can override them, it's often a better idea to shove those guts into an object and make that interface public. That way they can simply plug in a new object. For example, if you were writing a CD player and wanted the "go find info about this CD" bit customizable, rather than make those methods public you'd put all that functionality into its own object and make just your object getter/setter public. In this way being stingy about exposing your guts encourages good composition and separation of concerns

如果您希望用户能够自定义行为,而不是公开内部结构以便他们可以覆盖它们,那么将这些胆量推入一个对象并使该接口公开通常是一个更好的主意。这样他们就可以简单地插入一个新对象。例如,如果您正在编写 CD 播放器并希望“查找有关此 CD 的信息”位可定制,而不是将这些方法公开,您会将所有这些功能放入其自己的对象中,并仅将您的对象 getter/setter 公开. 通过这种方式,吝啬暴露你的胆量可以鼓励良好的构图和关注点的分离

Personally, I stick with just "private" and "public". Many OO languages just have that. "Protected" can be handy, but it's really a cheat. Once an interface is more than private it's outside of your control and you have to go looking in other people's code to find uses.

就个人而言,我坚持只使用“私人”和“公共”。许多面向对象的语言就是这样。“受保护”可能很方便,但它确实是个骗局。一旦接口不再是私有的,它就超出了您的控制范围,您必须查看其他人的代码才能找到用途。

This is where the idea of "published" comes in. Changing an interface (refactoring it) requires that you find all the code which is using it and change that, too. If the interface is private, well no problem. If it's protected you have to go find all your subclasses. If it's public you have to go find all the code which uses your code. Sometimes this is possible, for example if you're working on corporate code that's for internal use only it doesn't matter if an interface is public. You can grab all the code out of the corporate repository. But if an interface is "published", if there is code using it outside your control, then you're hosed. You must support that interface or risk breaking code. Even protected interfaces can be considered published (which is why I don't bother with protected).

这就是“已发布”的想法出现的地方。更改接口(重构它)需要您找到所有使用它的代码并对其进行更改。如果接口是私有的,那么没问题。如果它受到保护,你必须去寻找你所有的子类。如果它是公开的,您必须去查找使用您的代码的所有代码。有时这是可能的,例如,如果您正在处理仅供内部使用的公司代码,那么接口是否公开并不重要。您可以从公司存储库中获取所有代码。但是如果一个接口被“发布”,如果有代码在你的控制之外使用它,那么你就被灌输了。您必须支持该接口或冒破坏代码的风险。即使受保护的接口也可以被视为已发布(这就是为什么我不

Many languages find the hierarchical nature of public/protected/private to be too limiting and not in line with reality. To that end there is the concept of a trait class, but that's another show.

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

回答by Dov Wasserman

David's answer provides the meaning of each access modifier. As for when to use each, I'd suggest making public all classes and the methods of each class that are meant for external use (its API), and everything else private.

David 的回答提供了每个访问修饰符的含义。至于何时使用每个类,我建议将所有类和每个类的供外部使用(其 API)以及其他所有类的方法设为公开。

Over time you'll develop a sense for when to make some classes package-private and when to declare certain methods protected for use in subclasses.

随着时间的推移,您将了解何时将某些类设为包私有以及何时声明某些方法受保护以在子类中使用。

回答by dameng

This page writes well about the protected & default access modifier

此页面写得很好关于受保护和默认访问修饰符

.... Protected: Protected access modifier is the a little tricky and you can say is a superset of the default access modifier. Protected members are same as the default members as far as the access in the same package is concerned. The difference is that, the protected members are also accessible to the subclasses of the class in which the member is declared which are outside the package in which the parent class is present.

....受保护:受保护的访问修饰符有点棘手,您可以说是默认访问修饰符的超集。就同​​一包中的访问而言,受保护成员与默认成员相同。不同之处在于,受保护成员也可以被声明该成员的类的子类访问,这些子类位于父类所在的包之外。

But these protected members are “accessible outside the package only through inheritance“. i.e you can access a protected member of a class in its subclass present in some other package directly as if the member is present in the subclass itself. But that protected member will not be accessible in the subclass outside the package by using parent class's reference. ....

但是这些受保护的成员“只能通过继承在包外访问”。即,您可以直接访问某个其他包中存在的其子类中的类的受保护成员,就好像该成员存在于子类本身中一样。但是通过使用父类的引用,在包外的子类中将无法访问该受保护的成员。....

回答by Mechanical snail

It's actually a bit more complicated than a simple grid shows. The grid tells you whether an access is allowed, but what exactly constitutes an access? Also, access levels interact with nested classes and inheritance in complex ways.

它实际上比简单的网格显示要复杂一些。网格告诉您是否允许访问,但究竟什么构成访问?此外,访问级别以复杂的方式与嵌套类和继承交互。

The "default" access (specified by the absence of a keyword) is also called package-private. Exception: in an interface, no modifier means public access; modifiers other than public are forbidden. Enum constants are always public.

“默认”访问(由缺少关键字指定)也称为package-private。例外:在接口中,没有修饰符意味着公共访问;禁止使用 public 以外的修饰符。枚举常量总是公开的。

Summary

概括

Is an access to a member with this access specifier allowed?

是否允许使用此访问说明符访问成员?

  • Member is private: Only if member is defined within the same class as calling code.
  • Member is package private: Only if the calling code is within the member's immediately enclosing package.
  • Member is protected: Same package, or if member is defined in a superclass of the class containing the calling code.
  • Member is public: Yes.
  • 成员是private:仅当成员在与调用代码相同的类中定义时。
  • 成员是包私有的:仅当调用代码在成员的直接封闭包中时。
  • 成员是protected:相同的包,或者如果成员是在包含调用代码的类的超类中定义的。
  • 成员是public:是的。

What access specifiers apply to

访问说明符适用于什么

Local variables and formal parameters cannot take access specifiers. Since they are inherently inaccessible to the outside according to scoping rules, they are effectively private.

局部变量和形式参数不能采用访问说明符。由于根据范围规则,它们本质上是不可访问的,因此它们实际上是私有的。

For classes in the top scope, only publicand package-private are permitted. This design choice is presumably because protectedand privatewould be redundant at the package level (there is no inheritance of packages).

对于顶级范围内的类,只public允许和包私有。这种设计选择可能是因为protected并且private在包级别是多余的(没有包的继承)。

All the access specifiers are possible on class members (constructors, methods and static member functions, nested classes).

所有访问说明符都可以用于类成员(构造函数、方法和静态成员函数、嵌套类)。

Related: Java Class Accessibility

相关:Java 类可访问性

Order

命令

The access specifiers can be strictly ordered

访问说明符可以严格排序

public > protected > package-private > private

公共 > 受保护 > 包私有 > 私有

meaning that publicprovides the most access, privatethe least. Any reference possible on a private member is also valid for a package-private member; any reference to a package-private member is valid on a protected member, and so on. (Giving access to protected members to other classes in the same package was considered a mistake.)

意味着public提供最多的访问,private最少的。任何可能对私有成员的引用也对包私有成员有效;对包私有成员的任何引用在受保护成员上都是有效的,依此类推。(将受保护成员的访问权限授予同一包中的其他类被认为是错误的。)

Notes

笔记

  • A class's methods areallowed to access private members of other objects of the same class.More precisely, a method of class C can access private members of C on objects of any subclass of C. Java doesn't support restricting access by instance, only by class. (Compare with Scala, which does support it using private[this].)
  • You need access to a constructor to construct an object. Thus if all constructors are private, the class can only be constructed by code living within the class (typically static factory methods or static variable initializers). Similarly for package-private or protected constructors.
    • Only having private constructors also means that the class cannot be subclassed externally, since Java requires a subclass's constructors to implicitly or explicitly call a superclass constructor. (It can, however, contain a nested class that subclasses it.)
  • 类的方法允许访问同一类的其他对象的私有成员。更准确地说,类 C 的方法可以访问 C 的任何子类的对象上的私有成员。Java 不支持按实例限制访问,只能按类。(与 Scala 相比,它确实支持使用private[this].)
  • 您需要访问构造函数来构造对象。因此,如果所有构造函数都是私有的,则该类只能由类中的代码(通常是静态工厂方法或静态变量初始值设定项)来构造。对于包私有或受保护的构造函数也是如此。
    • 只有私有构造函数也意味着该类不能在外部进行子类化,因为 Java 需要子类的构造函数隐式或显式调用超类构造函数。(但是,它可以包含子类化它的嵌套类。)

Inner classes

内部类

You also have to consider nestedscopes, such as inner classes. An example of the complexity is that inner classes have members, which themselves can take access modifiers. So you can have a private inner class with a public member; can the member be accessed? (See below.) The general rule is to look at scope and think recursively to see whether you can access each level.

您还必须考虑嵌套作用域,例如内部类。复杂性的一个例子是内部类具有成员,这些成员本身可以使用访问修饰符。所以你可以有一个带有公共成员的私有内部类;可以访问会员吗?(见下文。)一般规则是查看范围并递归思考以查看您是否可以访问每个级别。

However, this is quite complicated, and for full details, consult the Java Language Specification. (Yes, there have been compiler bugs in the past.)

但是,这相当复杂,有关详细信息,请参阅 Java 语言规范。(是的,过去曾出现过编译器错误。)

For a taste of how these interact, consider this example. It is possible to "leak" private inner classes; this is usually a warning:

要了解这些交互方式,请考虑此示例。有可能“泄露”私有内部类;这通常是一个警告:

class Test {
    public static void main(final String ... args) {
        System.out.println(Example.leakPrivateClass()); // OK
        Example.leakPrivateClass().secretMethod(); // error
    }
}

class Example {
    private static class NestedClass {
        public void secretMethod() {
            System.out.println("Hello");
        }
    }
    public static NestedClass leakPrivateClass() {
        return new NestedClass();
    }
}

Compiler output:

编译器输出:

Test.java:4: secretMethod() in Example.NestedClass is defined in an inaccessible class or interface
        Example.leakPrivateClass().secretMethod(); // error
                                  ^
1 error

Some related questions:

一些相关问题:

回答by Ravi

In very short

简而言之

  • public: accessible from everywhere.
  • protected: accessible by the classes of the same package and the subclasses residing in any package.
  • default (no modifier specified): accessible by the classes of the same package.
  • private: accessible within the same class only.
  • public: 从任何地方都可以访问。
  • protected: 可由同一包的类和驻留在任何包中的子类访问。
  • 默认(未指定修饰符):可由同一包的类访问。
  • private: 只能在同一个类中访问。

回答by nxhoaf

As a rule of thumb:

根据经验:

  • private: class scope.
  • default(or package-private): package scope.
  • protected: package scope + child(like package, but we can subclass it from different packages). The protected modifier always keeps the "parent-child" relationship.
  • public: everywhere.
  • private: 类范围。
  • default(或package-private):包范围。
  • protected:(package scope + child就像包,但我们可以从不同的包中继承它)。protected 修饰符始终保持“父子”关系。
  • public: 无处不在。

As a result, if we divide access right into three rights:

因此,如果我们将访问权限划分为三个权限:

  • (D)irect(invoke from a method inside the same class, or via "this" syntax).
  • (R)eference(invoke a method using a reference to the class, or via "dot" syntax).
  • (I)nheritance(via subclassing).
  • (D) 直接(从同一类中的方法调用,或通过“this”语法调用)。
  • (R)eference(使用对类的引用或通过“点”语法调用方法)。
  • (I) 继承(通过子类化)。

then we have this simple table:

然后我们有这个简单的表:

+—-———————————————+————————————+———————————+
|                 |    Same    | Different |
|                 |   Package  | Packages  |
+—————————————————+————————————+———————————+
| private         |   D        |           |
+—————————————————+————————————+———————————+
| package-private |            |           |
| (no modifier)   |   D R I    |           |
+—————————————————+————————————+———————————+
| protected       |   D R I    |       I   |
+—————————————————+————————————+———————————+
| public          |   D R I    |    R  I   |
+—————————————————+————————————+———————————+

回答by Abdull

____________________________________________________________________
                | highest precedence <---------> lowest precedence
*———————————————+———————————————+———————————+———————————————+———————
 \ xCanBeSeenBy | this          | any class | this subclass | any
  \__________   | class         | in same   | in another    | class
             \  | nonsubbed     | package   | package       |    
Modifier of x \ |               |           |               |       
————————————————*———————————————+———————————+———————————————+———————
public          |       ?       |     ?     |       ?       |   ?  
————————————————+———————————————+———————————+———————————————+———————
protected       |       ?       |     ?     |       ?       |   ?   
————————————————+———————————————+———————————+———————————————+———————
package-private |               |           |               |
(no modifier)   |       ?       |     ?     |       ?       |   ?   
————————————————+———————————————+———————————+———————————————+———————
private         |       ?       |     ?     |       ?       |   ?    
____________________________________________________________________