在Java中,是否有明确规定何时使用每个访问修饰符,即默认(包私有),public
,protected
和private
,同时制作class
和interface
并处理继承?
The official tutorial可能对你有用。
______________________________________________________________ | │ Class │ Package │ Subclass │ Subclass │ World | | │ │ │(same pkg)│(diff pkg)│ | |───────────┼───────┼─────────┼──────────┼──────────┼────────| |public │ + │ + │ + │ + │ + | |───────────┼───────┼─────────┼──────────┼──────────┼────────| |protected │ + │ + │ + │ + │ | |───────────┼───────┼─────────┼──────────┼──────────┼────────| |no modifier│ + │ + │ + │ │ | |───────────┼───────┼─────────┼──────────┼──────────┼────────| |private │ + │ │ │ │ | |___________|_______|_________|__________|__________|________| + : accessible blank : not accessible
声明为private的方法,变量和构造函数只能在声明的类本身中访问。
专用访问修饰符是限制性最强的访问级别。类和接口不能是私有的。
注意
如果类中存在公共getter方法,则可以在类外部访问声明为private的变量。在超类中声明受保护的变量,方法和构造函数只能由其他包中的子类或受保护成员类的包中的任何类访问。
受保护的访问修饰符不能应用于类和接口。
方法,字段可以声明为protected,但是接口中的方法和字段不能声明为protected。
注意
受保护的访问权限使子类有机会使用辅助方法或变量,同时防止非相关类尝试使用它。
可以从任何其他类访问声明为public的类,方法,构造函数,接口等。
因此,可以从属于Java Universe的任何类访问在公共类中声明的字段,方法,块。
但是,如果我们尝试访问的公共类位于不同的包中,则仍需要导入公共类。
由于类继承,类的所有公共方法和变量都由其子类继承。
默认访问修饰符意味着我们没有为类,字段,方法等显式声明访问修饰符。
声明没有任何访问控制修饰符的变量或方法可用于同一包中的任何其他类。接口中的字段隐式为public static final,接口中的方法默认为public。
注意
我们不能覆盖静态字段。如果你试图覆盖它,它不显示任何错误,但它不起作用我们除外。
package sonpackage;
public class SomeClass
{
public void someMethod(Son s) throws Exception
{
s.foo(); // compilation error
}
}
Overriding static methods in java http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
私人:仅限课程访问
默认值(无修饰符):对类和包的访问受限
受保护:对类,包和子类的有限访问(包内和包外)
公共:可访问类,包(所有)和子类......简而言之,无处不在。
差异可以在已经提供的链接中找到,但使用的链接通常归结为“最少知识原则”。仅允许所需的最低可见性。
访问修饰符用于限制多个级别的访问。
公共:它基本上就像你可以从任何类访问一样简单,无论它是否在同一个包中。
要访问,如果您在同一个包中,则可以直接访问,但如果您在另一个包中,则可以创建该类的对象。
默认值:可以从任何类包中访问相同的包。
要访问,您可以创建该类的对象。但是您无法在包外部访问此变量。
受保护:您可以访问同一个包中的变量以及任何其他包中的子类。所以基本上它是默认+继承行为。
要访问基类中定义的受保护字段,可以创建子类的对象。
私有:它可以在同一个类中访问。
在非静态方法中,您可以直接访问因为此引用(也在构造函数中),但要在静态方法中访问,您需要创建类的对象。
Java中的访问修饰符。
Java访问修饰符用于在Java中提供访问控制。
1.默认:
只能访问同一个包中的类。
例如,
http://www.tutorialspoint.com/java/java_access_modifiers.htm
此访问比公共访问受到更多限制并受到保护,但受限于私有。
2.公开
可以从任何地方访问。 (全球访问)
例如,
// 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
}
}
输出:你好
3.私人
只能在同一个类中访问。
如果您尝试访问另一个类上的私有成员将抛出编译错误。例如,
// 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();
}
}
4.受保护
只能访问同一个包和子类中的类
例如,
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
}
}
输出:你好
// 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();
}
}
我只是想解决一个极其普遍错误的细节,包括本页面上的大部分答案。 “默认”访问(当不存在访问修饰符时)并不总是与package-private相同。这取决于事物是什么。
包装可见。默认。不需要修饰符。
仅对班级可见(私人)。
对世界可见(公众)。
包和所有子类(受保护)可见。
可以在不调用任何修饰符的情况下声明变量和方法。默认示例:
JLS §9.3 to 9.5
私人访问修饰符 - 私人:
声明为private的方法,变量和构造函数只能在声明的类本身中访问。私有访问修饰符是限制性最强的访问级别。类和接口不能是私有的。
如果类中存在公共getter方法,则可以在类外部访问声明为private的变量。
使用private修饰符是对象封装自身并隐藏来自外部世界的数据的主要方式。
例子:
String name = "john";
public int age(){
return age;
}
公共访问修饰符 - 公共:
可以从任何其他类访问声明为public的类,方法,构造函数,接口等。因此,可以从属于Java Universe的任何类访问在公共类中声明的字段,方法,块。
但是,如果我们尝试访问的公共类位于不同的包中,则仍需要导入公共类。
由于类继承,类的所有公共方法和变量都由其子类继承。
例:
Public class Details{
private String name;
public void setName(String n){
this.name = n;
}
public String getName(){
return this.name;
}
}
受保护的访问修饰符 - 受保护:
在超类中声明受保护的变量,方法和构造函数只能由另一个包中的子类或受保护成员类的包中的任何类访问。
受保护的访问修饰符不能应用于类和接口。方法,字段可以声明为protected,但是接口中的方法和字段不能声明为protected。
受保护的访问权限使子类有机会使用辅助方法或变量,同时防止非相关类尝试使用它。
public void cal(){
}
class Van{
protected boolean speed(){
}
}
class Car{
boolean speed(){
}
}
....受保护:受保护的访问修饰符有点棘手,你可以说是默认访问修饰符的超集。受保护的成员与默认成员相同,只要涉及相同包中的访问。不同之处在于,受保护成员也可以被声明成员的类的子类访问,这些成员位于父类所在的包之外。
但是这些受保护的成员“只能通过继承才能在程序包外部访问”。即,您可以直接访问其他包中存在的子类中受保护的成员,就好像该成员存在于子类本身中一样。但是,通过使用父类的引用,无法在包外部的子类中访问该受保护的成员。 ....
David的回答提供了每个访问修饰符的含义。至于何时使用每个,我建议公开所有类和每个类的方法以供外部使用(其API),以及其他所有私有。
随着时间的推移,您将了解何时将某些类包装为私有以及何时声明受保护以在子类中使用的某些方法。
(警告:我不是Java程序员,我是Perl程序员.Perl没有正式的保护,这也许是我理解这个问题的原因:))
就像你想的那样,只有声明它的类才能看到它。
只能被声明它的包看到和使用。这是Java中的默认值(有些人认为这是一个错误)。
Package Private +可以通过子类或包成员看到。
每个人都可以看到它。
在我控制的代码外可见。 (虽然不是Java语法,但对于这个讨论很重要)。
C ++定义了一个名为“friend”的附加级别,你知道的越少越好。
你什么时候应该用什么?整个想法是隐藏信息的封装。您希望尽可能隐藏用户完成某些操作的详细信息。为什么?因为那样你可以在以后更改它们而不会破坏任何人的代码。这使您可以优化,重构,重新设计和修复错误,而无需担心有人正在使用您刚刚彻底检查过的代码。
因此,经验法则是使事物只能像它们必须一样可见。从私有开始,只根据需要添加更多可见性。只有公开对用户来说绝对必要的内容,你公开的每一个细节都会让你重新设计系统。
如果您希望用户能够自定义行为,而不是将内部公开,以便他们可以覆盖它们,那么将这些内容推入对象并使该接口公开通常是一个更好的主意。这样他们就可以简单地插入一个新对象。例如,如果您正在编写CD播放器并希望“查找有关此CD的信息”位可自定义,而不是将这些方法公开,您可以将所有功能放入其自己的对象中,并使公共getter / setter公共对象。通过这种方式吝啬暴露你的胆量可以促进良好的成分和关注点的分离
就个人而言,我只坚持“私人”和“公开”。许多OO语言就是这样。 “受保护”可以派上用场,但这真的是一种骗局。一旦界面不仅仅是私人的,它就在你的控制之外,你必须去寻找其他人的代码才能找到用途。
这就是“已发布”的概念所在。更改界面(重构它)需要您找到使用它的所有代码并进行更改。如果界面是私有的,那么没问题。如果它受到保护,你必须找到你所有的子类。如果它是公开的,你必须找到使用你的代码的所有代码。有时这是可能的,例如,如果您正在处理仅供内部使用的公司代码,那么如果接口是公共的则无关紧要。您可以从公司存储库中获取所有代码。但是如果一个界面被“发布”,如果有代码在你的控制范围之外使用它,那么你就被软管了。您必须支持该接口或冒险破坏代码。甚至受保护的接口也可以被认为是已发布的(这就是我不打扰受保护的原因)。
许多语言发现公共/受保护/私有的等级性质太过限制而不符合现实。为此,有一个trait class的概念,但这是另一个节目。
注意:这只是对已接受答案的补充。
这与Java This page writes well about the protected & default access modifier有关。
Java访问修饰符指定哪些类可以访问给定的类及其字段,构造函数和方法。可以为类,其构造函数,字段和方法单独指定访问修饰符。 Java访问修饰符有时在日常语音中称为Java访问说明符,但正确的名称是Java访问修饰符。类,字段,构造函数和方法可以具有四种不同的Java访问修饰符之一:
- 项目清单
- 私人的
- 默认(包)
- 保护
- 上市
访问级别修饰符确定其他类是否可以使用特定字段或调用特定方法。访问控制有两个级别:
- 在顶层 - public或package-private(没有显式修饰符)。
- 在成员级别 - public,private,protected或package-private(无显式修饰符)。
可以使用修饰符public声明一个类,在这种情况下,该类对于所有类都可见。如果类没有修饰符(默认值,也称为包私有),则只能在其自己的包中显示
下表显示了每个修饰符允许的成员访问权限。
Controlling Access to Members of a Class第一个数据列指示类本身是否可以访问由访问级别定义的成员。如您所见,类始终可以访问自己的成员。第二列指示与该类相同的包中的类(无论其父级是否有)可以访问该成员。第三列指示在此包外声明的类的子类是否可以访问该成员。第四列指示是否所有类都可以访问该成员。
访问级别以两种方式影响您。首先,当您使用来自其他源的类(例如Java平台中的类)时,访问级别将确定您自己的类可以使用的这些类的哪些成员。其次,当您编写一个类时,您需要确定每个成员变量和类中的每个方法应具有的访问级别。
Public Protected Default和private是访问修饰符。
它们用于封装,或隐藏和显示类的内容。
在类外部无法访问私有默认值只能在包中访问。受保护的包以及任何扩展它的类。公众对所有人开放。
通常,成员变量是私有的,但成员方法是公共的。
我经常意识到,通过创造现实世界的类比,记住任何语言的基本概念都是可能的。以下是我在Java中理解访问修饰符的类比:
我们假设您是一所大学的学生,并且您有一位朋友将在周末来访您。假设校园中间有一座大学创始人的大型雕像。
希望这可以帮助!
当您考虑访问修饰符时,只需以这种方式考虑它(适用于变量和方法):
╔═════════════╦═══════╦═════════╦══════════╦═══════╗
║ 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 ║
╚═════════════╩═══════╩═════════╩══════════╩═══════╝
- >从每个地方都可以访问
public
- >只能在声明它的同一个类中访问
现在,当谈到private
和default
时会出现混乱
protected
- >没有访问修饰符关键字。这意味着它严格适用于该类包。在该软件包之外的任何地方都可以访问它。
default
- >比protected
稍微严格一点,除了相同的包类之外,它可以被声明的包外的子类访问。
这完全是关于封装(或者像乔菲利普斯所说的那样,知识最少)。
从限制性最强(私有)开始,看看以后是否需要限制较少的修饰符。
我们都使用方法和成员修饰符,如private,public,...但是开发人员做的一件事就是使用包来逻辑地组织代码。
例如:您可以将敏感的安全方法放在“安全”包中。然后放一个公共类来访问此包中的一些安全相关代码,但保持其他安全类包的私有性。因此,其他开发人员只能使用此包之外的公共类(除非他们更改修饰符)。这不是安全功能,但会指导使用。
default
另一件事是,彼此依赖很多的类可能最终在同一个包中,如果依赖性太强,最终可能会被重构或合并。
相反,如果将所有内容设置为公共内容,则不清楚应该或不应该访问的内容,这可能导致编写大量javadoc(它不会通过编译器执行任何操作......)。
Outside world -> Package (SecurityEntryClass ---> Package private classes)
下表总结了每个Java访问修饰符可应用于哪些Java构造:Jenkov's article
如果方法或变量被标记为私有(具有分配给它的私有访问修饰符),则只有同一类中的代码才能访问该变量,或者调用该方法。子类中的代码不能访问变量或方法,也不能从任何外部类编写代码。
无法使用私有访问修饰符标记类。使用私有访问修饰符标记一个类意味着没有其他类可以访问它,这意味着您根本无法真正使用该类。因此,类不允许使用私有访问修饰符。
通过不写任何访问修饰符来声明默认的Java访问修饰符。默认访问修饰符意味着类本身内的代码以及与此类相同的包中的类内的代码可以访问分配了默认访问修饰符的类,字段,构造函数或方法。因此,默认访问修饰符有时也称为包访问修饰符。
受保护的访问修饰符提供与默认访问修饰符相同的访问权限,并且子类可以访问超类的受保护方法和成员变量(字段)。即使子类与超类不在同一个包中,也是如此。
Java访问修饰符public意味着所有代码都可以访问类,字段,构造函数或方法,而不管访问代码的位置。访问代码可以在不同的类和不同的包中。
这是表格的更好版本。 (模块专栏的未来证明。)
i
)只能在声明的同一个类中访问。j
)的成员只能在同一个包中的类中访问。k
)可以在同一个包中的所有类中以及其他包中的子类中访问。l
)(除非它位于不导出声明的包的module中)。访问修饰符是一种帮助您防止意外破坏封装的工具(*)。问问自己,您是否希望该成员成为类,包,类层次结构内部或根本不是内部的内容,并相应地选择访问级别。
例子:
long internalCounter
应该是私有的,因为它是可变的和实现细节。void beforeRender()
方法应该受到保护。void saveGame(File dst)
方法应该是公共的。(*)Qazxswpoi
容易统治。首先声明一切都是私密的。然后随着需求的出现向公众发展,设计需要保证。
当暴露成员时,问问自己是否暴露了表示选择或抽象选择。第一个是你想要避免的东西,因为它会在实际表示中引入太多依赖,而不是它的可观察行为。
作为一般规则,我尝试通过子类化来避免覆盖方法实现;搞砸逻辑太容易了。如果要覆盖它,则声明抽象受保护的方法。
此外,在重写时使用@Override注释可以防止重构时出现问题。
它实际上比简单的网格显示要复杂一些。网格告诉您是否允许访问,但是访问的确切构成是什么?此外,访问级别以复杂的方式与嵌套类和继承交互。
“默认”访问(由缺少关键字指定)也称为 | 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 | ✔ | ✘ | ✘ | ✘
____________________________________________________________________
。例外:在界面中,没有修饰符意味着公共访问;禁止公开以外的修饰语。枚举常量总是公开的。
是否允许访问具有此访问说明符的成员?
private
:相同的包,或者如果成员是在包含调用代码的类的超类中定义的。protected
:是的。局部变量和形式参数不能使用访问说明符。由于根据范围规则它们本身就无法进入外部,因此它们实际上是私密的。
对于顶级作用域中的类,仅允许使用public
和package-private。这种设计选择可能是因为public
和protected
在包级别上是多余的(没有包的继承)。
所有访问说明符都可以在类成员(构造函数,方法和静态成员函数,嵌套类)上使用。
相关:private
访问说明符可以严格排序
public> protected> package-private> private
意思是Java Class Accessibility提供最多的访问,public
最少。私有成员可能的任何引用也对包私有成员有效;对包私有成员的任何引用在受保护的成员上都是有效的,依此类推。 (允许访问受保护的成员到同一个包中的其他类被认为是一个错误。)
private
更确切地说,类C的方法可以访问C的任何子类的对象上的C的私有成员.Java不支持通过实例限制访问,仅限于类。 (与Scala相比,它使用A class's methods are allowed to access private members of other objects of the same class.支持它。)您还必须考虑嵌套范围,例如内部类。复杂性的一个例子是内部类具有成员,这些成员本身可以使用访问修饰符。所以你可以拥有一个公共成员的私人内部阶级;会员可以访问吗? (见下文。)一般规则是查看范围并递归思考以查看是否可以访问每个级别。
然而,这是相当复杂的,并且对于详细信息,private[this]
。 (是的,过去有过编译器错误。)
要了解这些如何相互作用,请考虑此示例。有可能“泄漏”私人内部阶级;这通常是一个警告:
consult the Java Language Specification
编译器输出:
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
根据经验:
private
(或default
):包装范围。package-private
:protected
(与包一样,但我们可以从不同的包中继承它)。 protected修饰符始终保持“父子关系”。package scope + child
:无处不在。因此,如果我们将访问权限分为三个权限:
然后我们有这个简单的表:
public
很短的
+—-———————————————+————————————+———————————+
| | Same | Different |
| | Package | Packages |
+—————————————————+————————————+———————————+
| private | D | |
+—————————————————+————————————+———————————+
| package-private | | |
| (no modifier) | D R I | |
+—————————————————+————————————+———————————+
| protected | D R I | I |
+—————————————————+————————————+———————————+
| public | D R I | R I |
+—————————————————+————————————+———————————+
:无处不在。public
:可以通过相同包的类和驻留在任何包中的子类访问。protected
:只能在同一个班级内访问。Java中最容易被误解的访问修饰符是private
。我们知道它与默认修饰符类似,但有一个例外,即子类可以看到它。但是怎么样?这是一个有希望澄清混淆的例子:
protected
和Father
,每个都在自己的包装中:
Son
package fatherpackage;
public class Father
{
}
-------------------------------------------
package sonpackage;
public class Son extends Father
{
}
添加一个受保护的方法foo()
。
Father
package fatherpackage;
public class Father
{
protected void foo(){}
}
方法可以在4个上下文中调用:
在一个类中,该类位于定义foo()
的同一个包中(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();
}
}
在类型为父类的引用上,它位于定义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();
}
}
的包内(foo()
)[这可以包含在上下文中。 1]:
fatherpackage
package fatherpackage;
public class Son extends Father
{
public void sonMethod(Father f)
{
f.foo();
}
}
的包之外(foo()
):
fatherpackage
子类包内的非子类(子类从其父类继承受保护的成员,并使它们对非子类是私有的):
package sonpackage;
public class Son extends Father
{
public void sonMethod(Father f)
{
f.foo(); // compilation error
}
}