在Java中,在创建类和接口以及处理继承时,是否有明确的规则来确定何时使用每个访问修饰符,即默认的(包私有)、公共的、受保护的和私有的?
当前回答
作为经验法则:
private:类范围。默认(或包专用):包范围。protected:包范围+子级(类似于包,但我们可以从不同的包中对其进行子类化)。受保护的修饰符始终保持“父子”关系。公众:无处不在。
因此,如果我们将访问权分为三种权利:
(D) direct(从同一类内的方法调用,或通过“this”语法调用)。(R) reference(使用对类的引用或通过“dot”语法调用方法)。(一) 继承(通过子类化)。
那么我们有一个简单的表格:
+—-———————————————+————————————+———————————+
| | Same | Different |
| | Package | Packages |
+—————————————————+————————————+———————————+
| private | D | |
+—————————————————+————————————+———————————+
| package-private | | |
| (no modifier) | D R I | |
+—————————————————+————————————+———————————+
| protected | D R I | I |
+—————————————————+————————————+———————————+
| public | D R I | R I |
+—————————————————+————————————+———————————+
其他回答
这是该表的一个更好的版本,其中还包括一个模块列。
解释
私有成员(i)只能在声明的同一类中访问。没有访问修饰符(j)的成员只能在同一包中的类中访问。受保护的成员(k)可以在同一包中的所有类和其他包中的子类中访问。公共成员(l)对所有类都是可访问的(除非它驻留在不导出声明它的包的模块中)。
要选择哪个修饰符?
访问修饰符是一种帮助您防止意外破坏封装(*)的工具。问问自己,您是否希望成员是类、包、类层次结构的内部成员,或者根本不是内部成员,并相应地选择访问级别。
示例:
长字段internalCounter可能应该是私有的,因为它是可变的,并且是实现细节。只应在工厂类中实例化的类(在同一个包中)应具有包限制构造函数,因为不可能从包外部直接调用它。应保护在呈现之前调用并用作子类中钩子的内部void beforeRender()方法。从GUI代码调用的void saveGame(File dst)方法应该是公共的。
(*)封装到底是什么?
David的回答提供了每个访问修饰符的含义。至于何时使用每一个,我建议公开所有用于外部使用的类和每个类的方法(其API),并将其他所有内容私有化。
随着时间的推移,您将了解何时将某些类包设为私有,以及何时声明某些方法受保护以便在子类中使用。
简单的规则。首先声明所有内容都是私有的。然后,随着需求的出现和设计的需要,向公众迈进。
当公开成员时,问问自己是公开表示选择还是抽象选择。第一种是您需要避免的,因为它会引入太多对实际表示的依赖,而不是对其可观察行为的依赖。
作为一般规则,我试图通过子类化来避免重写方法实现;搞砸逻辑太容易了。如果要重写抽象受保护的方法,请声明该方法。
此外,在重写时使用@Override注释,以防止重构时出错。
此页很好地描述了受保护的默认访问修饰符(&D)
....受保护:受保护的访问修饰符有点棘手,可以说是默认访问修饰符的超集。就同一包中的访问而言,受保护的成员与默认成员相同。不同的是,受保护的成员也可以访问声明成员的类的子类,这些子类位于父类所在的包之外。
但是,这些受保护的成员“只能通过继承在包外部访问”。即,您可以直接访问某个类的子类中的受保护成员,就像该成员存在于子类本身中一样。但是,通过使用父类的引用,该受保护成员在包外部的子类中将无法访问。....
对于初学者来说,考虑这个例子可能会有所帮助;
考虑到我在foo包中开发了MyClass,它有一个很棒的方法,名为print,您有兴趣调用它(它可能是一个方法或属性)
package foo; // I am in foo
public class MyClass {
private void print() { //This is private
System.out.println("I can print!");
}
}
您已经开发了YourClass的bar包,您有兴趣使用MyClass#print
package bar; \\You are not in same package as me
import foo.MyClass;
public class YourClass {
void test() {
MyClass myClass = new MyClass();
myClass.print();
}
}
您的代码未编译,并且出现错误。方法print()对于类型MyClass未定义
你来找我:
你:我想用你的方法,但它是私人的。你能公开吗?我:不,我不想让别人使用你:我是你的朋友,至少让我不要让别人使用它。我:好的,我将删除私有关键字。我的访问修饰符将是默认的或私有的包。因为你们是我的朋友,你们必须和我在同一个包裹里。所以你们必须来到我的包裹里。我的意思是确切的包,甚至不是子包。
然后MyClass将
package foo;
public class MyClass {
void print() { //No access modifier means default or package-private
System.out.println("I can print!");
}
}
YourClass将是:
package foo;//You come to my package
public class YourClass {
void test() {
MyClass myClass = new MyClass();
myClass.print();
}
}
不考虑这个:你又来找我了
你:我的老板告诉我我不能改变我的包(在实际世界中,你不能改变你的包以使用其他类方法)我:还有另一种方法,如果你扩展我,我使print()受到保护,那么无论你是否更改包,你都可以使用它。(因此,子类将始终允许您访问我的方法)。
这是我的班级
package foo;
protected class MyClass { // it is now protected
protected void print() {
System.out.println("I can print!");
}
}
这是YourClass
package bar; // You are on your own package
import foo.MyClass;
public class YourClass extends MyClass {
void test() {
//You initiate yourself! But as you extend me you can call my print()
YourClass yourClass = new YourClass();
yourClass.print();
}
}
您可能已经注意到,通过使一个方法受到保护,所有其他类都可以通过扩展它来使用它,您无法轻松控制如何使用它。这在java17中通过引入密封和许可词来解决。因此,您可以定义哪些类可以扩展您。类似于公共密封类MyClass允许YourClass参见Java17中的密封类是什么?有关详细信息
推荐文章
- 如何格式化Joda-Time DateTime仅为mm/dd/yyyy?
- 如何在POM.xml中引用环境变量?
- 如何在android中复制一个文件?
- 将整数转换为字符串,以逗号表示千
- 接口方法的最终参数-有什么意义?
- Java中的@UniqueConstraint注释
- 如何在清洁模式下运行eclipse ?如果我们这样做会发生什么?
- 获取java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory异常
- Java中的正则表达式命名组
- c#和Java的主要区别是什么?
- 什么是NullPointerException,我如何修复它?
- 在Java中使用“final”修饰符
- 无法在Flutter上找到捆绑的Java版本
- 如何在Kotlin解析JSON ?
- 如何在新的材质主题中改变背面箭头的颜色?