在Java中,默认,公共,受保护和私有之间的区别
在Java中,在制定class
和interface
以及处理inheritance时,是否明确规定何时使用每个访问修饰符,即默认(package private), public
, protected
和private
?
官方教程可能对你有一些用处。
| 类| 包| 子类| 子类| 世界 | | |(same pkg)|(diff pkg)| ------------ + ------- + --------- + ---------- + -------- - + -------- 公共| + | + | + | + | + ------------ + ------- + --------- + ---------- + -------- - + -------- 保护| + | + | + | + | ------------ + ------- + --------- + ---------- + -------- - + -------- 没有修饰符| + | + | + | | ------------ + ------- + --------- + ---------- + -------- - + -------- 私人| + | | | | +:可以访问 空白:不可访问
(注意:我不是Java程序员,我是Perl程序员,Perl没有正式的保护措施,这也许是为什么我理解这个问题的原因:))
私人的
就像你会想的那样,只有宣布的类才能看到它。
套餐私人
只能被声明的包所看到和使用。 这是Java中的默认(有些人认为是错误的)。
受保护
Package Private +可以被子类或包成员看到。
上市
每个人都可以看到它。
发布时间
在我控制的代码之外可见。 (虽然不是Java语法,但是这个讨论很重要)。
C ++定义了一个名为“朋友”的额外级别,你知道的越less越好。
你什么时候该用什么? 整个想法是隐藏信息的封装。 尽可能多的你想隐藏你的用户如何做的细节。 为什么? 因为那么你可以稍后改变它们而不会破坏任何人的代码。 这可以让您优化,重构,重新devise和修复错误,而不用担心有人使用刚刚检修过的代码。
所以,经验法则是让事物看起来像是必须的。 从私人开始,只需要添加更多的可见性。 只有公开那些对用户来说绝对必要的知识,你公开的每一个细节都会激发你重新devise系统的能力。
如果您希望用户能够自定义行为,而不是公开内部以便它们可以覆盖它们,那么将这些内容推入对象并公开该接口通常是一个更好的主意。 这样他们可以简单地插入一个新的对象。 例如,如果您正在编写CD播放器,并希望“查找有关此CD的信息”位可自定义,而不是将这些方法公开,则可以将所有function放入其自己的对象中,并只公开您的对象getter / setter 。 以这种方式暴露你的胆量鼓励良好的构成和关注的分离小气
我个人坚持“私人”和“公共”。 许多面向对象的语言就是这样。 “保护”可以方便,但它真的是一个骗子。 一旦一个界面不仅仅是私人界面,而且你还不得不去寻找其他人的代码来寻找用途。
这就是“发布”这个概念的来源。改变一个接口(重构它)需要你find所有使用它的代码并改变它。 如果接口是私人的,那么没问题。 如果它被保护,你必须去find你所有的子类。 如果它是公开的,你必须find所有使用你的代码的代码。 有时这是可能的,例如,如果您正在处理仅供内部使用的公司代码,则无论接口是否公开都无关紧要。 您可以从公司存储库中获取所有代码。 但是,如果一个接口是“发布”,如果有代码使用它在你的控制之外,那么你会被洗脑。 您必须支持该界面或冒险破坏代码。 即使受保护的接口可以被认为是公布的(这就是为什么我不打扰受保护)。
许多语言都认为公共/保护/私人的等级性太过于限制,不符合实际。 为此,有一个特质类的概念,但这是另一个表演。
这是一个更好的表格。 (未来certificate与模块列)
说明
-
一个私人成员只能在声明的同一个类中访问。
-
没有访问修饰符的成员只能在相同包中的类中访问。
-
受保护的成员可以在同一包中的所有类中访问,也可以在其他包中的子类内访问。
-
所有类都可以访问公共成员(除非它驻留在不导出声明包的模块中)。
select哪个修饰符?
访问修饰符是帮助您防止意外破坏封装(*)的工具 。 问问你自己是否打算让这个成员成为class级,包裹,class级内部的东西或者根本不在内部,并相应地select访问级别。
例子:
- 一个字段
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 | ✔ | ✘ | ✘ | ✘
轻松的规则。 首先宣布一切私密。 然后随着需求的增加向公众推进并devise保证。
当暴露成员问自己,如果你是暴露代表select或抽象select。 第一个是你想要避免的,因为它会在实际表示中引入过多的依赖关系,而不是在其可观察到的行为上。
作为一般规则,我尝试通过子类避免重写方法实现; 这太容易搞砸了逻辑。 声明抽象的保护方法,如果你打算重写。
重写时还要使用@Override注释以防止重构时发生中断。
这实际上比简单的网格显示要复杂一点。 网格告诉你是否允许访问,但访问是什么? 另外,访问级别以复杂的方式与嵌套类和inheritance进行交互。
“缺省”访问(由缺less关键字指定)也称为包私有 。 例外:在一个界面中,没有修饰符意味着公共访问; 禁止公众以外的其他修饰语。 枚举常量总是公开的。
概要
是否允许访问具有此访问说明符的成员?
- 成员是
private
:只有当成员在与调用代码相同的类中被定义时。 - 成员是包私有的:只有当调用代码在成员的立即封闭包内。
- 成员被
protected
:相同的包,或者如果成员在包含调用代码的类的超类中定义。 - 成员是
public
:是的。
什么访问说明符适用于
局部variables和forms参数不能使用访问说明符。 由于它们根据范围规则在内部是不可见的,所以它们是有效的私人的。
对于顶级范围中的类,只允许public
和私有包。 这种deviseselect大概是因为protected
和private
在包级别是多余的(没有包的inheritance)。
所有访问说明符都可能在类成员(构造函数,方法和静态成员函数,嵌套类)上。
相关: Java类辅助function
订购
访问说明符可以严格sorting
public> protected> package-private> private
这意味着public
提供的访问最多, private
最less。 私人会员可能提供的任何参考也适用于私人会员; 任何对包私有成员的引用在受保护的成员上都是有效的,依此类推。 (将受保护的成员访问到同一包中的其他类中被认为是错误的)。
笔记
- 一个类的方法被允许访问同一类的其他对象的私有成员。 更确切地说,类C的方法可以访问C的任何子类的对象上的C的私有成员。Java不支持通过实例来限制访问,只能通过类。 (与Scala相比,Scala支持使用
private[this]
。 - 你需要访问一个构造函数来构造一个对象。 因此,如果所有的构造函数都是私有的,那么类只能由类中的代码(通常是静态工厂方法或静态variables初始值设定器)构造。 类似于包私有或受保护的构造函数。
- 只有私有构造函数也意味着该类不能被外部子类化,因为Java要求子类的构造函数隐式地或显式地调用超类构造函数。 (但是,它可以包含一个嵌套类,它是子类的)。
内部类
您还必须考虑嵌套的作用域,例如内部类。 一个复杂的例子就是内部类有成员,他们自己可以访问修饰符。 所以你可以有一个公共成员的私人内部类。 会员可以访问吗? (见下文)一般规则是查看范围并recursion思考是否可以访问每个级别。
但是,这是相当复杂的,有关详细信息, 请参阅Java语言规范 。 (是的,过去有编译器bug。)
想了解这些如何相互作用,请考虑这个例子。 有可能“泄漏”私人内部课堂; 这通常是一个警告:
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 – 包私有类中的方法可访问性?
根据经验:
- 私人 :课堂范围。
- 默认 (或包私有 ):包的范围。
- 保护 :包范围+孩子 (像包,但我们可以从不同的包子类)。 受保护的修饰符总是保持“父子关系”。
- 公众 :无处不在。
因此,如果我们将访问权分为三种权利:
- (D)直接 (从同一个类中的一个方法调用)。
- (R)eference (使用对类的引用或通过“点”语法来调用方法)。
- (I)inheritance (通过inheritance )。
那么我们有这个简单的表格:
在很短的时间内
-
public
:无处不在。 -
protected
:可以通过同一包中的类和任何包中的子类访问。 - 默认(没有指定修饰符):可以被同一个包的类访问。
-
private
:只能在同一个class级内访问。
Java中最容易被误解的访问修饰符是protected
。 我们知道它与默认修饰符类似,只有一个例外,子类可以看到它。 但是,如何? 这是一个希望澄清混淆的例子:
-
假设我们有两个类;
Father
和Son
,每个都有自己的包装:package fatherpackage; public class Father { } ------------------------------------------- package sonpackage; public class Son extends Father { }
-
让我们向
Father
添加一个受保护的方法foo()
。package fatherpackage; public class Father { protected void foo(){} }
-
foo()
方法可以在4个上下文中调用:-
在位于与
foo()
定义的相同包中的类(fatherpackage
)中:package fatherpackage; public class SomeClass { public void someMethod(Father f, Son s) { f.foo(); s.foo(); } }
-
在子类中,在当前实例中通过
this
或者super
:package sonpackage; public class Son extends Father { public void sonMethod() { this.foo(); super.foo(); } }
-
在types是相同类的引用上:
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(); } }
-
在types是父类的引用上,它是在定义了
foo()
的包foo()
父包)中的。[可以包含在上下文no中。 1]:package fatherpackage; public class Son extends Father { public void sonMethod(Father f) { f.foo(); } }
-
-
以下情况无效。
-
在types是父类的引用上,它在
foo()
被定义(fatherpackage
包foo()
的包之外 :package sonpackage; public class Son extends Father { public void sonMethod(Father f) { f.foo(); // compilation error } }
-
一个子类包内的非子类(一个子类从父类inheritance受保护的成员,并且使它们对于非子类是私有的):
package sonpackage; public class SomeClass { public void someMethod(Son s) throws Exception { s.foo(); // compilation error } }
-
私人的
- 方法,variables和构造函数
被声明为私有的方法,variables和构造函数只能在声明的类本身内访问。
- 类和接口
私人访问修饰符是最严格的访问级别。 类和接口不能是私有的。
注意
如果公共getter方法存在于类中,那么声明为private的variables可以在类外部访问。 在超类中声明保护的variables,方法和构造函数只能由其他包中的子类或受保护成员类的包中的任何类访问。
受保护
- 类和接口
受保护的访问修饰符不能应用于类和接口。
方法,字段可以声明为protected,但是接口中的方法和字段不能声明为protected。
注意
受保护的访问使子类有机会使用助手方法或variables,同时防止不相关的类尝试使用它。
上市
公开的类,方法,构造函数,接口等可以从任何其他类访问。
因此,在公共类中声明的字段,方法,块可以从属于Java Universe的任何类访问。
- 不同的包
但是,如果我们试图访问的公共类是在不同的包中,那么公共类仍然需要导入。
由于类的inheritance,一个类的所有公共方法和variables都被它的子类inheritance。
默认 – 没有关键字:
默认访问修饰符意味着我们不显式声明一个类,字段,方法等的访问修饰符。
- 在相同的软件包
没有任何访问控制修饰符声明的variables或方法可用于同一个包中的任何其他类。 接口中的字段隐式地为public static final,接口中的方法默认为public。
注意
我们不能覆盖静态fields.if你试图覆盖它不显示任何错误,但它不工作,除了我们除了。
相关答案
- 在java中重写静态方法
参考链接
http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html http://www.tutorialspoint.com/java/java_access_modifiers.htm
不同的地方可以在已经提供的链接中find,但是使用哪一个通常归结为“最小知识原则”。 只允许最需要的可见性。
私人 :只限上课
缺省值(无修饰符) :对类和包的访问权限有限
受保护 :对类,包和子类(内部和外部包)
公开 :可以上课,包(全部)和子类…总之,无处不在。
访问修饰符可以在几个层次上限制访问。
公开:基本上就像你可以从任何class级访问一样简单,无论是否在同一个包中。
要访问,如果你在同一个包,你可以直接访问,但如果你在另一个包,那么你可以创build一个类的对象。
默认值:可以从任何类的包中访问。
访问你可以创build一个类的对象。 但是你不能在包之外访问这个variables。
受保护:您可以访问同一包中的variables以及任何其他包中的子类。 所以基本上它是默认+inheritance行为。
要访问在基类中定义的受保护字段,您可以创build子类的对象。
私人:它可以在同一个class级访问。
在非静态方法中,您可以直接访问,因为此引用(也在构造函数中),但要访问静态方法,您需要创build类的对象。
可见的包。 默认。 不需要修饰符。
仅对class级可见( 私人 )。
对世界可见( 公众 )。
可见包和所有子类( 受保护 )。
可以声明variables和方法,而不用调用任何修饰符。 默认示例:
String name = "john"; public int age(){ return age; }
私人访问修饰符 – 私有:
被声明为private的方法,variables和构造函数只能在声明的类本身中访问。 私人访问修饰符是最严格的访问级别。 类和接口不能是私有的。
如果公共getter方法存在于类中,那么声明为private的variables可以在类外部访问。
使用私有修饰符是对象封装自己并隐藏外部数据的主要方式。
例子:
Public class Details{ private String name; public void setName(String n){ this.name = n; } public String getName(){ return this.name; } }
公共访问修饰符 – public:
公开的类,方法,构造函数,接口等可以从任何其他类访问。 因此,在公共类中声明的字段,方法,块可以从属于Java宇宙的任何类访问。
但是,如果我们尝试访问的公共类处于不同的包中,那么公共类仍然需要导入。
由于类的inheritance,一个类的所有公共方法和variables都被它的子类inheritance。
例:
public void cal(){ }
受保护的访问修饰符 – 保护:
在超类中声明保护的variables,方法和构造函数只能由其他包中的子类或受保护成员类的包中的任何类访问。
受保护的访问修饰符不能应用于类和接口。 方法,字段可以声明为protected,但是接口中的方法和字段不能声明为protected。
受保护的访问使子类有机会使用助手方法或variables,同时防止不相关的类尝试使用它。
class Van{ protected boolean speed(){ } } class Car{ boolean speed(){ } }
在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 } }
这种访问比公共和受保护更受限制,但比私人受限制更less。
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级内进入。
如果你尝试访问另一个类中的私有成员将抛出编译错误。 例如,
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(); } }
输出:你好
我只是想解决一个非常常见的错误,包括本页面的大部分答案。 “默认”访问(不存在访问修饰符时)并不总是与包私有相同 。 这取决于事情是什么。
-
非成员types(即类,枚举,接口和注释types未在另一types中声明)默认情况下是包私有的。 ( JLS§6.6.1 )
-
类成员和构造函数默认是包私有的。 ( JLS§6.6.1 )
-
枚举构造函数默认是私有的 。 (的确,枚举构造函数必须是私有的,试图使它们公开或保护是错误的)。 枚举常量是公共的,不允许任何访问说明符。 枚举的其他成员默认情况下是包私有的。 ( JLS§8.9 )
-
接口和注释types的所有成员默认是公共的 。 (事实上,接口和注解types的成员必须是公共的,并且试图使其成为私有或保护是错误的。)( JLS§9.3到9.5 )
-
公开 – 可以从应用程序的任何地方访问。
-
默认 – 从包中可访问。
-
保护 – 可以从其他包中的包和子类访问。 以及
-
私人 – 只能从其class级访问。
大卫的答案提供了每个访问修饰符的含义。 至于什么时候使用,我build议公开所有的类和每个类的外部使用方法(API),其他所有的东西都是私有的。
随着时间的推移,你将开发一个感觉什么时候做一些类包私有,什么时候声明某些方法保护在子类中使用。
这个页面写了关于保护和默认访问修饰符
….保护:受保护的访问修饰符是有点棘手,你可以说是默认访问修饰符的超集。 就同一包中的访问而言,受保护的成员与默认成员相同。 所不同的是,被保护的成员也可以被声明成员的类的子类访问,而父类所在的包之外。
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. ….
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)
- 保护
- 上市
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.
- Class can be public or default
- 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.
- 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 beprotected
orpublic
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.
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.
Default: When no access modifier is specified for a class , method or data member – It is said to be having the default access modifier by default. The data members, class or methods which are not declared using any access modifiers ie having default access modifier are accessible only within the same package. Private: The private access modifier is specified using the keyword private. The methods or data members declared as private are accessible only within the class in which they are declared. Any other class of same package will not be able to access these members. Classes or interface can not be declared as private. protected: The protected access modifier is specified using the keyword protected. The methods or data members declared as protected are accessible within same package or sub classes in different package. public: The public access modifier is specified using the keyword public. The public access modifier has the widest scope among all other access modifiers. Classes, methods or data members which are declared as public are accessible from every where in the program. There is no restriction on the scope of a public data members.