在Java中,有没有关于何时使用每个访问修饰符,即默认明确的规则(包私有)public
,protected
并且private
,同时使class
与interface
和处理继承?
官方教程可能对你有用.
______________________________________________________________ | ? Class ? Package ? Subclass ? Subclass ? World | | ? ? ?(same pkg)?(diff pkg)? | |????????????????????????????????????????????????????????????| |public ? + ? + ? + ? + ? + | |????????????????????????????????????????????????????????????| |protected ? + ? + ? + ? + ? | |????????????????????????????????????????????????????????????| |no modifier? + ? + ? + ? ? | |????????????????????????????????????????????????????????????| |private ? + ? ? ? ? | |___________|_______|_________|__________|__________|________| + : accessible blank : not accessible
(警告:我不是Java程序员,我是Perl程序员.Perl没有正式的保护,这也许是我理解这个问题的原因:))
就像你想的那样,只有声明它的类才能看到它.
只能被声明它的包看到和使用.这是Java中的默认值(有些人认为这是一个错误).
Package Private +可以通过子类或包成员看到.
每个人都可以看到它.
在我控制的代码之外可见.(虽然不是Java语法,但对于这个讨论很重要).
C++定义了一个名为"friend"的附加级别,你知道的越少越好.
你什么时候应该用什么?整个想法是隐藏信息的封装.您希望尽可能隐藏用户完成某些操作的详细信息.为什么?因为那样你可以在以后更改它们而不会破坏任何人的代码.这使您可以优化,重构,重新设计和修复错误,而无需担心有人正在使用您刚刚彻底检查过的代码.
因此,经验法则是使事物只能像它们必须一样可见.从私有开始,只根据需要添加更多可见性.只有公开对用户来说绝对必要的内容,你公开的每一个细节都会让你重新设计系统.
如果您希望用户能够自定义行为,而不是将内部公开,以便他们可以覆盖它们,那么将这些内容推入对象并使该接口公开通常是一个更好的主意.这样他们就可以简单地插入一个新对象.例如,如果您正在编写CD播放器并希望"查找有关此CD的信息"位可自定义,而不是将这些方法公开,您可以将所有功能放入其自己的对象中,并使公共getter/setter成为公共对象.通过这种方式吝啬暴露你的胆量可以促进良好的成分和关注点的分离
就个人而言,我只坚持"私人"和"公开".许多OO语言就是这样."受保护"可以派上用场,但这真的是一种骗局.一旦界面不仅仅是私人的,它就在你的控制之外,你必须去寻找其他人的代码才能找到用途.
这就是"已发布"的概念所在.更改界面(重构它)需要您找到使用它的所有代码并进行更改.如果界面是私有的,那么没问题.如果它受到保护,你必须找到你所有的子类.如果它是公开的,你必须找到使用你的代码的所有代码.有时这是可能的,例如,如果您正在处理仅供内部使用的公司代码,那么如果接口是公共的则无关紧要.您可以从公司存储库中获取所有代码.但是如果一个界面被"发布",如果有代码在你的控制范围之外使用它,那么你就被软管了.您必须支持该接口或冒险破坏代码.即使是受保护的界面也可以被认为是已发布的(这就是我不喜欢
许多语言发现公共/受保护/私有的等级性质太过限制而不符合现实.为此,有一个特质类的概念,但这是另一个节目.
这是表格的更好版本.(模块专栏的未来证明.)
一个私有成员(i
)是唯一的,因为它宣布同一个类中访问.
没有访问修饰符(j
)的成员只能在同一个包中的类中访问.
一个受保护的成员(k
)是在同一个包中的所有类中访问和其他包中的子类中.
一个公共成员(l
)是所有类都可以访问(除非它驻留在一个模块不出口,现声明在包).
访问修饰符是一种帮助您防止意外破坏封装的工具(*).问问自己,您是否希望该成员成为类,包,类层次结构内部或根本不是内部的内容,并相应地选择访问级别.
例子:
字段long internalCounter
应该是私有的,因为它是可变的和实现细节.
只应在工厂类(在同一个包中)实例化的类应具有包受限构造函数,因为不应该直接从包外部调用它.
void beforeRender()
在呈现之前调用并在子类中用作钩子的内部方法应该受到保护.
void saveGame(File dst)
从GUI代码调用的方法应该是公共的.
(*)什么是封装?
| 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注释.
它实际上比简单的网格显示要复杂一些.网格告诉您是否允许访问,但是访问的确切构成是什么?此外,访问级别以复杂的方式与嵌套类和继承交互.
"默认"访问(由缺少关键字指定)也称为package-private.例外:在界面中,没有修饰符意味着公共访问; 禁止公开以外的修饰语.枚举常量总是公开的.
是否允许访问具有此访问说明符的成员?
成员是private
:仅当成员与调用代码在同一类中定义时.
成员是包私有:仅当调用代码在成员的立即封装包内时.
成员是protected
:相同的包,或者如果成员是在包含调用代码的类的超类中定义的.
成员是public
:是的.
局部变量和形式参数不能使用访问说明符.由于根据范围规则它们本身就无法进入外部,因此它们实际上是私密的.
对于顶级作用域中的类,仅public
允许使用package-private.这种设计选择大概是因为protected
并且private
在包级别上是多余的(没有包的继承).
所有访问说明符都可以在类成员(构造函数,方法和静态成员函数,嵌套类)上使用.
相关:Java类可访问性
访问说明符可以严格排序
public> protected> package-private> private
意味着public
提供最多的访问,private
至少.私有成员可能的任何引用也对包私有成员有效; 对包私有成员的任何引用在受保护的成员上都是有效的,依此类推.(允许访问受保护的成员到同一个包中的其他类被认为是一个错误.)
类的方法是允许访问同一类的其他对象的私有成员.更准确地说,C类的方法只能通过类来访问的C私有成员C.爪哇任子类的对象不支持通过实例限制访问.(与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:包范围+子(如包,但我们可以从不同的包中继承它).protected修饰符始终保持"父子关系".
公众:无处不在.
因此,如果我们将访问权限分为三个权限:
(D)irect(从同一个类中的方法调用).
(R)eference(使用对类的引用或通过"dot"语法调用方法).
(I)nheritance(通过子类化).
然后我们有这个简单的表:
+—-———————————————+————————————+———————————+ | | 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
:可以通过相同包的类和驻留在任何包中的子类访问.
default(未指定修饰符):可由同一包的类访问.
private
:只能在同一个类中访问.
Java中最容易被误解的访问修饰符是protected
.我们知道它与默认修饰符类似,但有一个例外,即子类可以看到它.但是怎么样?这是一个有希望澄清混淆的例子:
假设我们有2个班级; Father
并且Son
,每个都在自己的包装中:
package fatherpackage; public class Father { } ------------------------------------------- package sonpackage; public class Son extends Father { }
让我们添加一个受保护的方法foo()
来Father
.
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(); } }
在类型相同的引用上:
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()
定义(fatherpackage
)[这可以包含在上下文中.1]:
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 } }
子类包内的非子类(子类从其父类继承受保护的成员,并使它们对非子类是私有的):
package sonpackage; public class SomeClass { public void someMethod(Son s) throws Exception { s.foo(); // compilation error } }
方法,变量和构造函数
声明为private的方法,变量和构造函数只能在声明的类本身中访问.
类和接口
专用访问修饰符是限制性最强的访问级别.类和接口不能是私有的.
注意
如果类中存在公共getter方法,则可以在类外部访问声明为private的变量.在超类中声明受保护的变量,方法和构造函数只能由其他包中的子类或受保护成员类的包中的任何类访问.
类和接口
受保护的访问修饰符不能应用于类和接口.
方法,字段可以声明为protected,但是接口中的方法和字段不能声明为protected.
注意
受保护的访问使子类有机会使用辅助方法或变量,同时防止非相关类尝试使用它.
可以从任何其他类访问声明为public的类,方法,构造函数,接口等.
因此,可以从属于Java Universe的任何类访问在公共类中声明的字段,方法,块.
不同的包
但是,如果我们尝试访问的公共类位于不同的包中,则仍需要导入公共类.
由于类继承,类的所有公共方法和变量都由其子类继承.
默认访问修饰符意味着我们没有为类,字段,方法等显式声明访问修饰符.
在同一个包中
声明没有任何访问控制修饰符的变量或方法可用于同一包中的任何其他类.接口中的字段隐式为public static final,接口中的方法默认为public.
注意
我们不能覆盖静态字段.如果你试图覆盖它,它不显示任何错误,但它不起作用我们除外.
覆盖java中的静态方法
http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html http://www.tutorialspoint.com/java/java_access_modifiers.htm
的差异可以在链接中找到已经提供,但使用哪一个通常归结为"至少意味着知识的原则".仅允许所需的最低可见性.
私人:仅限课程访问
默认值(无修饰符):对类和包的访问受限
受保护:对类,包和子类的有限访问(包内和包外)
公共:可访问类,包(所有)和子类......简而言之,无处不在.
访问修饰符用于限制多个级别的访问.
Public:它基本上就像你可以从任何类访问一样简单,无论是否在同一个包中.
要访问,如果您在同一个包中,则可以直接访问,但如果您在另一个包中,则可以创建该类的对象.
默认值:可以从任何类包中访问相同的包.
要访问,您可以创建该类的对象.但是您无法在包外部访问此变量.
受保护:您可以访问同一个包中的变量以及任何其他包中的子类.所以基本上它是默认+继承行为.
要访问基类中定义的受保护字段,可以创建子类的对象.
私有: 它可以在同一个类中访问.
在非静态方法中,您可以直接访问因为此引用(也在构造函数中),但要在静态方法中访问,您需要创建类的对象.
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(); } }
输出:你好
包装可见.默认.不需要修饰符.
仅对班级可见(私人).
对世界可见(公众).
对包和所有子类(受保护)可见.
可以在不调用任何修饰符的情况下声明变量和方法.默认示例:
String name = "john"; public int age(){ return age; }
私人访问修饰符 - 私人:
声明为private的方法,变量和构造函数只能在声明的类本身中访问.私有访问修饰符是限制性最强的访问级别.类和接口不能是私有的.
如果类中存在公共getter方法,则可以在类外部访问声明为private的变量.
使用private修饰符是对象封装自身并隐藏来自外部世界的数据的主要方式.
例子:
Public class Details{ private String name; public void setName(String n){ this.name = n; } public String getName(){ return this.name; } }
公共访问修饰符 - 公共:
可以从任何其他类访问声明为public的类,方法,构造函数,接口等.因此,可以从属于Java Universe的任何类访问在公共类中声明的字段,方法,块.
但是,如果我们尝试访问的公共类位于不同的包中,则仍需要导入公共类.
由于类继承,类的所有公共方法和变量都由其子类继承.
例:
public void cal(){ }
受保护的访问修饰符 - 受保护:
在超类中声明受保护的变量,方法和构造函数只能由另一个包中的子类或受保护成员类的包中的任何类访问.
受保护的访问修饰符不能应用于类和接口.方法,字段可以声明为protected,但是接口中的方法和字段不能声明为protected.
受保护的访问使子类有机会使用辅助方法或变量,同时防止非相关类尝试使用它.
class Van{ protected boolean speed(){ } } class Car{ boolean speed(){ } }
公共 - 可从应用程序的任何位置访问.
默认 - 可从包中访问.
protected - 可从其他包中的包和子类访问.同样
私人 - 仅限同类课程.
我只是想解决一个极其普遍错误的细节,包括本页面上的大部分答案."默认"访问(当不存在访问修饰符时)并不总是与package-private相同.这取决于事物是什么.
非成员类型(即,未在另一种类型中声明的类,枚举,接口和注释类型)默认为package-private.(JLS§6.6.1)
默认情况下,类成员和构造函数是包私有的.(JLS§6.6.1)
枚举构造函数默认是私有的.(实际上,枚举结构必须是私有的,尝试将它们公开或保护是错误的).枚举常量是公共的,不允许任何访问说明符.枚举的其他成员默认为package-private.(JLS§8.9)
默认情况下,接口和注释类型的所有成员都是公共的.(实际上,接口和注释类型的成员必须是公共的,并且尝试将它们设为私有或受保护是错误的.)(JLS§9.3至9.5)
此页面很好地描述了受保护和默认访问修饰符
....受保护:受保护的访问修饰符有点棘手,你可以说是默认访问修饰符的超集.受保护的成员与默认成员相同,只要涉及相同包中的访问.不同之处在于,受保护成员也可以被声明成员的类的子类访问,这些成员位于父类所在的包之外.
但是这些受保护的成员"只能通过继承才能在程序包外部访问".即,您可以直接访问其他包中存在的子类中受保护的成员,就好像该成员存在于子类本身中一样.但是,通过使用父类的引用,无法在包外部的子类中访问该受保护的成员.....
David的回答提供了每个访问修饰符的含义.至于何时使用每个,我建议公开所有类和每个类的方法以供外部使用(其API),以及其他所有私有.
随着时间的推移,您将了解何时将某些类包装为私有以及何时声明受保护以在子类中使用的某些方法.
注意:这只是对已接受答案的补充.
这与Java Access Modifiers有关.
从Java Access修饰符:
Java访问修饰符指定哪些类可以访问给定的类及其字段,构造函数和方法.可以为类,其构造函数,字段和方法单独指定访问修饰符.Java访问修饰符有时在日常语音中称为Java访问说明符,但正确的名称是Java访问修饰符.类,字段,构造函数和方法可以具有四种不同的Java访问修饰符之一:
项目清单
私人的
默认(包)
保护
上市
从控制对类成员的访问教程:
访问级别修饰符确定其他类是否可以使用特定字段或调用特定方法.访问控制有两个级别:
在顶层 - public或package-private(没有显式修饰符).
在成员级别 - public,private,protected或package-private(无显式修饰符).
可以使用修饰符public声明一个类,在这种情况下,该类对于所有类都可见.如果类没有修饰符(默认值,也称为包私有),则只能在其自己的包中显示
下表显示了每个修饰符允许的成员访问权限.
???????????????????????????????????????????????????? ? 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 ? ????????????????????????????????????????????????????第一个数据列指示类本身是否可以访问由访问级别定义的成员.如您所见,类始终可以访问自己的成员.第二列指示与该类相同的包中的类(无论其父级是否有)可以访问该成员.第三列指示在此包外声明的类的子类是否可以访问该成员.第四列指示是否所有类都可以访问该成员.
访问级别以两种方式影响您.首先,当您使用来自其他源的类(例如Java平台中的类)时,访问级别将确定您自己的类可以使用的这些类的哪些成员.其次,当您编写一个类时,您需要确定每个成员变量和类中的每个方法应具有的访问级别.
Public Protected Default和private是访问修饰符.
它们用于封装,或隐藏和显示类的内容.
类可以是公共的或默认的
类成员可以是公共的,受保护的,默认的或私有的.
在类外部无法访问私有默认值只能在包中访问.受保护的包以及任何扩展它的类.公众对所有人开放.
通常,成员变量是私有的,但成员方法是公共的.
我经常意识到,通过创造现实世界的类比,记住任何语言的基本概念都是可能的.以下是我在Java中理解访问修饰符的类比:
我们假设您是一所大学的学生,并且您有一位朋友将在周末来访您.假设校园中间有一座大学创始人的大型雕像.
当你把他带到校园时,你和你朋友看到的第一件事就是这座雕像.这意味着任何走进校园的人都可以在未经大学许可的情况下观看雕像.这使雕像成为PUBLIC.
接下来,你想把你的朋友带到你的宿舍,但为此你需要将他注册为访客.这意味着他可以获得进入通行证(与您的通行证相同)进入校园内的各种建筑物.这将使他的访问卡成为PROTECTED.
您的朋友想要登录校园WiFi,但没有任何凭据可以登录.他上网的唯一方法就是与他分享您的登录信息.(请记住,每个上大学的学生也拥有这些登录凭据).这将使您的登录凭据为NO MODIFIER.
最后,您的朋友想要阅读您在网站上发布的学期的进度报告.但是,每个学生都有自己的个人登录信息,可以访问校园网站的这一部分.这将使这些凭据成为PRIVATE.
希望这可以帮助!