Java中的public,protected,package-private和private有什么区别?

在Java中,是否有明确的规则来确定何时使用每个访问修饰符,即默认(包私有), publicprotectedprivate ,同时创建classinterface以及处理inheritance?

官方教程可能对你有用。

             │class级│包装│子类│子类│世界
             │││(相同的pkg)│(diff pkg)│ 
 ────────────┼───────┼─────────┼──────────┼──────── ──┼────────
公开│+│+│+│+│+     
 ────────────┼───────┼─────────┼──────────┼──────── ──┼────────
受保护的│+│+│+│+│         
 ────────────┼───────┼─────────┼──────────┼──────── ──┼────────
没有修饰符│+│+│+││    
 ────────────┼───────┼─────────┼──────────┼──────── ──┼────────
私人│+││││    

 +:可访问
空白:无法访问

(警告:我不是Java程序员,我是Perl程序员.Perl没有正式的保护,这也许是我理解这个问题的原因:))

私人的

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

包私人

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

受保护

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

上市

每个人都可以看到它。

发布时间

在我控制的代码外面可见。 (虽然不是Java语法,但对于此讨论非常重要)。

C ++定义了一个名为“friend”的附加级别,你知道的越少越好。

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

因此,经验法则是使事物只能像它们必须一样可见。 从私有开始,只根据需要添加更多可见性。 只公开那些对用户来说绝对必要的信息,你公开的每一个细节都会让你重新设计系统。

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

就个人而言,我坚持只是“私人”和“公共”。 许多OO语言就是这样。 “受保护”可以派上用场,但这真的是一种骗局。 一旦界面不仅仅是私人的,它就在你的控制之外,你必须去寻找其他人的代码才能找到用途。

这就是“已发布”的概念所在。更改界面(重构它)需要您找到使用它的所有代码并进行更改。 如果界面是私有的,那么没问题。 如果它受到保护,你必须找到你所有的子类。 如果它是公开的,你必须找到使用你的代码的所有代码。 有时这是可能的,例如,如果您正在处理仅供内部使用的公司代码,那么如果接口是公共的则无关紧要。 您可以从公司存储库中获取所有代码。 但是如果一个界面被“发布”,如果有代码在你的控制范围之外使用它,那么你就被软管了。 您必须支持该接口或冒险破坏代码。 甚至受保护的接口也可以被认为是已发布的(这就是我不打扰受保护的原因)。

许多语言发现公共/受保护/私有的等级性质太过限制而不符合现实。 为此,有一个特质类的概念,但这是另一个节目。

这是表格的更好版本。 (模块专栏的未来certificate。)

Java Access Modifiers

说明

  • 私有成员只能在声明的同一个类中访问。

  • 没有访问修饰符的成员只能在同一个包中的类中访问。

  • 受保护的成员可以在同一个包中的所有类中以及其他包中的子类中访问。

  • 所有类都可以访问公共成员(除非它驻留在不导出声明的包的模块中)。


选择哪种修饰符?

访问修饰符是一种帮助您防止意外破坏封装的工具(*) 。 问问自己,您是否希望该成员成为类,包,类层次结构内部的内容,或者根本不是内部成员,并相应地选择访问级别。

例子:

  • 字段long internalCounter应该是私有的,因为它是可变的和实现细节。
  • 只应在工厂类(在同一个包中)实例化的类应具有包受限制的构造函数,因为不应该直接从包外部调用它。
  • 在渲染之前调用并在子类中用作钩子的内部void beforeRender()方法应该受到保护。
  • 从GUI代码调用的void saveGame(File dst)方法应该是公共的。

(*) 什么是封装?

  | 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 | ✔ | ✘ | ✘ | ✘ 

简单的规则。 首先声明一切都是私密的。 然后随着需求的出现向公众发展,设计需要保证。

当暴露成员时,问问自己是否暴露了表示选择或抽象选择。 第一个是你想要避免的东西,因为它会在实际表示中引入太多依赖,而不是它的可观察行为。

作为一般规则,我尝试通过子类化来避免重写方法实现; 搞砸逻辑太容易了。 如果要覆盖它,则声明抽象受保护的方法。

此外,在重写时使用@Override注释可以防止重构时出现问题。

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

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

概要

是否允许访问具有此访问说明符的成员?

  • 成员是private :仅当成员与调用代码在同一个类中定义时。
  • 成员是包私有:仅当调用代码在成员的立即封装包内时。
  • 成员protected :相同的包,或者如果成员是在包含调用代码的类的超类中定义的。
  • 会员是public :是的。

什么访问说明符适用于

局部变量和forms参数不能使用访问说明符。 由于根据范围规则它们本身就无法进入外部,因此它们实际上是私密的。

对于顶级作用域中的类,只允许使用public和package-private。 这种设计选择可能是因为protectedprivate在包级别上是多余的(没有包的inheritance)。

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

相关: Java类可访问性

订购

访问说明符可以严格排序

public> protected> package-private> private

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

笔记

  • 允许类的方法访问同一类的其他对象的私有成员。 更确切地说,类C的方法可以访问C的任何子类的对象上的C的私有成员.Java不支持通过实例限制访问,仅限于类。 (与Scala相比,它使用private[this]支持它。)
  • 您需要访问构造函数才能构造对象。 因此,如果所有构造函数都是私有的,则该类只能由生活在类中的代码构造(通常是静态工厂方法或静态变量初始化器)。 类似地,对于包私有或受保护的构造函数。
    • 只有私有构造函数也意味着该类不能在外部进行子类化,因为Java需要子类的构造函数来隐式或显式地调用超类构造函数。 (但是,它可以包含一个嵌套类,它将它子类化。)

内课

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

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

要了解这些如何相互作用,请考虑此示例。 有可能“泄漏”私人内部阶级; 这通常是一个警告:

 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(); } } 

编译器输出:

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

一些相关问题:

  • Java – 包私有类中的方法可访问性?

根据经验:

  • private :类范围。
  • default (或package-private ):包范围。
  • protected :包范围+子 (如包,但我们可以从不同的包中inheritance它)。 protected修饰符始终保持“父子关系”。
  • 公众 :无处不在。

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

  • (D)irect (从同一个类中的方法调用)。
  • (R)eference (使用对类的引用或通过“点”语法调用方法)。
  • (I)nheritance (通过子类化)。

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

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

很短的

  • public :无处不在。
  • protected :可由同一个包的类和驻留在任何包中的子类访问。
  • default(未指定修饰符):可由同一包的类访问。
  • private :只能在同一个class级内访问。

Java中最容易被误解的访问修饰符protected 。 我们知道它与默认修饰符类似,但有一个例外,即子类可以看到它。 但是怎么样? 这是一个有希望澄清混淆的例子:

  • 假设我们有2个class级; FatherSon ,每个都在自己的包装中:

     package fatherpackage; public class Father { } ------------------------------------------- package sonpackage; public class Son extends Father { } 
  • 让我们为Father添加一个受保护的方法foo()

     package fatherpackage; public class Father { protected void foo(){} } 
  • 方法foo()可以在4个上下文中调用:

    1. 在一个类中,该类位于定义了foo()的同一个包中( fatherpackage ):

       package fatherpackage; public class SomeClass { public void someMethod(Father f, Son s) { f.foo(); s.foo(); } } 
    2. 在子类内部,通过thissuper在当前实例上:

       package sonpackage; public class Son extends Father { public void sonMethod() { this.foo(); super.foo(); } } 
    3. 在类型相同的引用上:

       package fatherpackage; public class Father { public void fatherMethod(Father f) { f.foo(); // valid even if foo() is private } } ------------------------------------------- package sonpackage; public class Son extends Father { public void sonMethod(Son s) { s.foo(); } } 
    4. 在类型为父类的引用上,它位于包中,其中定义了foo()fatherpackage )[这可以包含在上下文中。 1]:

       package fatherpackage; public class Son extends Father { public void sonMethod(Father f) { f.foo(); } } 
  • 以下情况无效。

    1. 在类型为父类的引用上,它位于定义了foo()的包之外fatherpackage ):

       package sonpackage; public class Son extends Father { public void sonMethod(Father f) { f.foo(); // compilation error } } 
    2. 子类包内的非子类(子类从其父类inheritance受保护的成员,并使它们对非子类是私有的):

       package sonpackage; public class SomeClass { public void someMethod(Son s) throws Exception { s.foo(); // compilation error } } 

私人的

  • 方法,变量和构造函数

声明为private的方法,变量和构造函数只能在声明的类本身中访问。

  • 类和接口

专用访问修饰符是限制性最强的访问级别。 类和接口不能是私有的。

注意

如果类中存在公共getter方法,则可以在类外部访问声明为private的变量。 在超类中声明受保护的变量,方法和构造函数只能由其他包中的子类或受保护成员类的包中的任何类访问。


受保护

  • 类和接口

受保护的访问修饰符不能应用于类和接口。

方法,字段可以声明为protected,但是接口中的方法和字段不能声明为protected。

注意

受保护的访问权限使子类有机会使用辅助方法或变量,同时防止非相关类尝试使用它。


上市

可以从任何其他类访问声明为public的类,方法,构造函数,接口等。

因此,可以从属于Java Universe的任何类访问在公共类中声明的字段,方法,块。

  • 不同的包

但是,如果我们尝试访问的公共类位于不同的包中,则仍需要导入公共类。

由于类inheritance,类的所有公共方法和变量都由其子类inheritance。


默认-No关键字:

默认访问修饰符意味着我们没有为类,字段,方法等显式声明访问修饰符。

  • 在同一个包中

声明没有任何访问控制修饰符的变量或方法可用于同一包中的任何其他类。 接口中的字段隐式为public static final,接口中的方法默认为public。

注意

我们不能覆盖静态字段。如果你试图覆盖它,它不显示任何错误,但它不起作用我们除外。

相关答案

  • 覆盖java中的静态方法

参考链接

http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html http://www.tutorialspoint.com/java/java_access_modifiers.htm

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

私人 :仅限课程访问

默认值(无修饰符) :对类和包的访问受限

受保护 :对类,包和子类的有限访问(包内和包外)

公共 :可访问类,包(所有)和子类……简而言之,无处不在。

Java中的访问修饰符。

Java访问修饰符用于在Java中提供访问控制。

1.默认:

只能访问同一个包中的类。

例如,

 // Saved in file A.java package pack; class A{ void msg(){System.out.println("Hello");} } // Saved in file B.java package mypack; import pack.*; class B{ public static void main(String args[]){ A obj = new A(); // Compile Time Error obj.msg(); // Compile Time Error } } 

此访问比公共访问受到更多限制并受到保护,但受限于私有。

2.公开

可以从任何地方访问。 (全球访问)

例如,

 // Saved in file A.java package pack; public class A{ public void msg(){System.out.println("Hello");} } // Saved in file B.java package mypack; import pack.*; class B{ public static void main(String args[]){ A obj = new A(); obj.msg(); } } 

输出:你好

3.私人

只能在同一个类中访问。

如果您尝试访问另一个类中的私有成员将导致编译错误。 例如,

 class A{ private int data = 40; private void msg(){System.out.println("Hello java");} } public class Simple{ public static void main(String args[]){ A obj = new A(); System.out.println(obj.data); // Compile Time Error obj.msg(); // Compile Time Error } } 

4.受保护

只能访问同一个包和子类中的类

例如,

 // Saved in file A.java package pack; public class A{ protected void msg(){System.out.println("Hello");} } // Saved in file B.java package mypack; import pack.*; class B extends A{ public static void main(String args[]){ B obj = new B(); obj.msg(); } } 

输出:你好

在此输入图像描述

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

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

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

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

要访问,您可以创建该类的对象。 但是您无法在包外部访问此变量。

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

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

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

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

包装可见。 默认值。 不需要修饰符。

仅对class级可见( 私人 )。

对世界可见( 公众 )。

包和所有子类( 受保护 )可见。

可以在不调用任何修饰符的情况下声明变量和方法。 默认示例:

 String name = "john"; public int age(){ return age; } 

私人访问修饰符 – 私有:

声明为private的方法,变量和构造函数只能在声明的类本身中访问。 私有访问修饰符是限制性最强的访问级别。 类和接口不能是私有的。

Variables that are declared private can be accessed outside the class if public getter methods are present in the class.

Using the private modifier is the main way that an object encapsulates itself and hides data from the outside world.

例子:

 Public class Details{ private String name; public void setName(String n){ this.name = n; } public String getName(){ return this.name; } } 

Public access modifier – public:

A class, method, constructor, interface, etc. declared public can be accessed from any other class. Therefore fields, methods, blocks declared inside a public class can be accessed from any class belonging to the Java universe.

However, if the public class we are trying to access is in a different package, then the public class still need to be imported.

Because of class inheritance, all public methods and variables of a class are inherited by its subclasses.

例:

 public void cal(){ } 

Protected access modifier – protected:

Variables, methods and constructors which are declared protected in a superclass can be accessed only by the subclasses in another package or any class within the package of the protected members’ class.

The protected access modifier cannot be applied to class and interfaces. Methods, fields can be declared protected, however methods and fields in a interface cannot be declared protected.

Protected access gives the subclass a chance to use the helper method or variable, while preventing a nonrelated class from trying to use it.

 class Van{ protected boolean speed(){ } } class Car{ boolean speed(){ } } 
  • public – accessible from anywhere in the application.

  • default – accessible from package.

  • protected – accessible from package and sub-classes in other package. as well

  • private – accessible from its class only.

I just want to address a detail that is extremely commonly got wrong, including by most of the answers on this page. “Default” access (when no access modifier is present) is not always the same as package-private . It depends on what the thing is.

  • Non-member types (that is, classes, enums, interfaces, and annotation types not declared inside another type) are package-private by default. ( JLS §6.6.1 )

  • Class members and constructors are package-private by default. ( JLS §6.6.1 )

  • Enum constructors are private by default . (Indeed, enum contructors must be private, and it is an error to try to make them public or protected). Enum constants are public, and do not allow any access specifier. Other members of enums are package-private by default. ( JLS §8.9 )

  • All members of interfaces and annotation types are public by default . (Indeed, members of interfaces and annotation types must be public, and it is an error to try to make them private or protected.) ( JLS §9.3 to 9.5 )

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“. ie 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. ….

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.

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.

  • Visible to the package. the default . No modifiers are needed.
  • Visible to the class only; private .
  • Visible to the world; public .
  • Visible to the package and all subclasses; protected .

So let’s talk about Access Control and Inheritance The following rules for inherited methods are,

  • Methods declared public in a superclass also must be public in all subclasses.
  • Methods declared protected in a superclass must either be protected or public in subclasses; they cannot be private.
  • Methods declared without access control (no modifier was used) can be declared more private in subclasses.
  • Methods declared private are not inherited at all, so there is no rule for them.

Note: This is just a supplement for the accepted answer.

This is related to Java Access Modifiers .

From Java Access Modifiers :

A Java access modifier specifies which classes can access a given class and its fields, constructors and methods. Access modifiers can be specified separately for a class, its constructors, fields and methods. Java access modifiers are also sometimes referred to in daily speech as Java access specifiers, but the correct name is Java access modifiers. Classes, fields, constructors and methods can have one of four different Java access modifiers:

  • 项目清单
  • 私人的
  • default (package)
  • protected
  • 上市

From Controlling Access to Members of a Class tutorials:

Access level modifiers determine whether other classes can use a particular field or invoke a particular method. There are two levels of access control:

  • At the top level—public, or package-private (no explicit modifier).
  • At the member level—public, private, protected, or package-private (no explicit modifier).

A class may be declared with the modifier public, in which case that class is visible to all classes everywhere. If a class has no modifier (the default, also known as package-private), it is visible only within its own package

The following table shows the access to members permitted by each modifier.

 ╔═════════════╦═══════╦═════════╦══════════╦═══════╗ ║ Modifier ║ Class ║ Package ║ Subclass ║ World ║ ╠═════════════╬═══════╬═════════╬══════════╬═══════╣ ║ public ║ Y ║ Y ║ Y ║ Y ║ ║ protected ║ Y ║ Y ║ Y ║ N ║ ║ no modifier ║ Y ║ Y ║ N ║ N ║ ║ private ║ Y ║ N ║ N ║ N ║ ╚═════════════╩═══════╩═════════╩══════════╩═══════╝ 

The first data column indicates whether the class itself has access to the member defined by the access level. As you can see, a class always has access to its own members. The second column indicates whether classes in the same package as the class (regardless of their parentage) have access to the member. The third column indicates whether subclasses of the class declared outside this package have access to the member. The fourth column indicates whether all classes have access to the member.

Access levels affect you in two ways. First, when you use classes that come from another source, such as the classes in the Java platform, access levels determine which members of those classes your own classes can use. Second, when you write a class, you need to decide what access level every member variable and every method in your class should have.

Public Protected Default and private are access modifiers.

They are meant for encapsulation, or hiding and showing contents of the class.

  1. Class can be public or default
  2. Class members can be public, protected, default or private.

Private is not accessible outside the class Default is accessible only in the package. Protected in package as well as any class which extends it. Public is open for all.

Normally, member variables are defined private, but member methods are public.

Often times I’ve realized that remembering the basic concepts of any language can made possible by creating real-world analogies. Here is my analogy for understanding access modifiers in Java:

Let’s assume that you’re a student at a university and you have a friend who’s coming to visit you over the weekend. Suppose there exists a big statue of the university’s founder in the middle of the campus.

  • When you bring him to the campus, the first thing that you and your friend sees is this statue. This means that anyone who walks in the campus can look at the statue without the university’s permission. This makes the statue as PUBLIC .

  • Next, you want to take your friend to your dorm, but for that you need to register him as a visitor. This means that he gets an access pass (which is the same as yours) to get into various buildings on campus. This would make his access card as PROTECTED .

  • Your friend wants to login to the campus WiFi but doesn’t have the any credentials to do so. The only way he can get online is if you share your login with him. (Remember, every student who goes to the university also possesses these login credentials). This would make your login credentials as NO MODIFIER .

  • Finally, your friend wants to read your progress report for the semester which is posted on the website. However, every student has their own personal login to access this section of the campus website. This would make these credentials as PRIVATE .

希望这可以帮助!

When you are thinking of access modifiers just think of it in this way (applies to both variables and methods ):

public –> accessible from every where
private –> accessible only within the same class where it is declared

Now the confusion arises when it comes to default and protected

default –> No access modifier keyword is present. This means it is available strictly within the package of the class. Nowhere outside that package it can be accessed.

protected –> Slightly less stricter than default and apart from the same package classes it can be accessed by sub classes outside the package it is declared.

It is all about encapsulation (or as Joe Phillips stated, least knowledge ).

Start with the most restrictive (private) and see if you need less restrictive modifiers later on.

We all use method and member modifiers like private, public, … but one thing too few developers do is use packages to organize code logically.

For example: You may put sensitive security methods in a ‘security’ package. Then put a public class which accesses some of the security related code in this package but keep other security classes package private . Thus other developers will only be able to use the publicly available class from outside of this package (unless they change the modifier). This is not a security feature, but will guide usage.

 Outside world -> Package (SecurityEntryClass ---> Package private classes) 

Another thing is that classes which depend a lot on each other may end up in the same package and could eventually be refactored or merged if the dependency is too strong.

If on the contrary you set everything as public it will not be clear what should or should not be accessed, which may lead to writing a lot of javadoc (which does not enforce anything via the compiler…).