在Java中,在创建类和接口以及处理继承时,是否有明确的规则来确定何时使用每个访问修饰符,即默认的(包私有)、公共的、受保护的和私有的?
当前回答
简单的规则。首先声明所有内容都是私有的。然后,随着需求的出现和设计的需要,向公众迈进。
当公开成员时,问问自己是公开表示选择还是抽象选择。第一种是您需要避免的,因为它会引入太多对实际表示的依赖,而不是对其可观察行为的依赖。
作为一般规则,我试图通过子类化来避免重写方法实现;搞砸逻辑太容易了。如果要重写抽象受保护的方法,请声明该方法。
此外,在重写时使用@Override注释,以防止重构时出错。
其他回答
平民的如果用public声明类成员,则可以从任何地方访问它受保护的如果用关键字protected声明类成员,则可以从相同的类成员、同一包内的外部类成员和继承的类成员访问该类成员。如果类成员受到保护,则不能从外部包类访问它,除非外部包类被继承,即扩展其他包超类。但是,受保护的类成员始终可用于相同的包类,无论是否继承了相同的包类别违约在Java中,默认值不是访问修饰符关键字。如果声明的类成员没有任何访问修饰符关键字,那么在这种情况下,它被视为默认成员。默认类成员始终可用于相同的包类成员。但即使外部类是与受保护成员不同的子类,外部包类成员也不能访问默认类成员私有的如果用关键字protected声明了类成员,那么在这种情况下,它只对相同的类成员可用
(注意:我不是一个Java程序员,我是一个Perl程序员。Perl没有正式的保护措施,这也许就是为什么我如此理解这个问题的原因:)
私有的
就像你想的那样,只有声明它的类才能看到它。
包专用
它只能由声明它的包看到和使用。这是Java中的默认设置(有些人认为这是错误的)。
受保护的
包Private+可以由子类或包成员看到。
平民的
每个人都能看到。
出版
在我控制的代码之外可见。(虽然不是Java语法,但这对本次讨论很重要)。
C++定义了一个称为“朋友”的附加级别,你对它了解得越少越好。
你什么时候应该用什么?整个想法是封装以隐藏信息。您希望尽可能地向用户隐藏某些操作的细节。为什么?因为这样你以后就可以更改它们,而不会破坏任何人的代码。这使您可以优化、重构、重新设计和修复错误,而不用担心有人在使用您刚刚大修过的代码。
因此,经验法则是让事物尽可能地可见。从私密开始,只在需要时增加更多的可见性。只公开用户需要知道的信息,你公开的每一个细节都限制了你重新设计系统的能力。
如果您希望用户能够自定义行为,而不是将内部公开以便他们可以覆盖它们,那么通常最好将这些内容插入到对象中并将接口公开。这样他们就可以简单地插入一个新对象。例如,如果您正在编写一个CD播放器,并希望“go find info about this CD”位可定制,而不是将这些方法公开,那么您应该将所有这些功能放入其对象中,并仅将对象getter/setter公开。通过这种方式,吝啬于暴露自己的内心会鼓励良好的组合和关注的分离
我只坚持“私人”和“公共”。许多OO语言都有这一点。“受保护”可能很方便,但这是一个骗局。一旦一个接口超过了私有,它就超出了你的控制范围,你必须去查看其他人的代码才能找到用途。
这就是“发布”的概念所在。更改接口(重构它)需要找到使用它的所有代码并进行更改。如果接口是私有的,那么没问题。如果它受到保护,你必须找到所有的子类。如果它是公开的,你必须找到使用你的代码的所有代码。有时这是可能的,例如,如果您正在编写仅供内部使用的公司代码,那么接口是否公开无关紧要。您可以从公司存储库中获取所有代码。但是,如果一个接口被“发布”,如果有代码在您的控制之外使用它,那么您将被罚款。您必须支持该接口,否则可能会破坏代码。即使是受保护的接口也可以被认为是已发布的(这就是为什么我不关心受保护的)。
许多语言发现公共/受保护/私有的等级性质过于局限,不符合现实。为此,有一种特质类的概念,但这是另一种表现。
我的两分钱:)
私人:
class->顶级类不能是私有的。内部类可以是私有的,可以从同一类访问。
实例变量->只能在类中访问。无法在类外部访问。
包专用:
class->顶级类可以是包专用的。它只能从同一个包访问。不是来自子包装,不是来自外包装。
实例变量->可从同一包访问。不是来自子包装,不是来自外包装。
受保护的:
class->无法保护顶级类。
实例变量->只能在同一包或子包中访问。扩展类时只能在包外部访问。
公众:
类->可从包/子包/另一个包访问
实例变量->可从包/子包/另一个包访问
下面是详细的答案
https://github.com/junto06/java-4-beginners/blob/master/basics/access-modifier.md
对于初学者来说,考虑这个例子可能会有所帮助;
考虑到我在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中的密封类是什么?有关详细信息
区别可以在已经提供的链接中找到,但使用哪一个链接通常取决于“最少知识原则”。只允许所需的最小可见性。
推荐文章
- 在流中使用Java 8 foreach循环移动到下一项
- 访问限制:'Application'类型不是API(必需库rt.jar的限制)
- 用Java计算两个日期之间的天数
- 如何配置slf4j-simple
- 在Jar文件中运行类
- 带参数的可运行?
- 我如何得到一个字符串的前n个字符而不检查大小或出界?
- 我可以在Java中设置enum起始值吗?
- Java中的回调函数
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 在Java中,流相对于循环的优势是什么?
- Jersey在未找到InjectionManagerFactory时停止工作
- 在Java流是peek真的只是调试?
- Recyclerview不调用onCreateViewHolder
- 将JSON字符串转换为HashMap