我最近在学习Java,我遇到了package-private
类的概念,如果我们没有指定任何内容,这是默认的。但后来我才意识到:
我很少看到使用package-private类。是否有这样的理由,例如,它有严重的缺点,它是多余的,或者只是我阅读不够?是否有强烈支持/反对其使用的论据?
如果在大多数情况下它真的没用,为什么它会是默认值?
在什么情况下我们应该在现实世界中使用package-private?即,什么时候会变得不可替代?
换句话说,默认的package-private修饰符的主要优点和缺点是什么?
答案 0 :(得分:51)
简短的回答是 - 这是一种稍微宽泛的私人形式。
我假设您熟悉public
和private
之间的区别,以及为什么制作方法和变量private
通常是好的做法仅用于相关课程的内部。
嗯,作为对此的扩展 - 如果您正在考虑以模块化方式创建软件,您可能会考虑到模块的公共接口,其中包含多个类他们之间的合作。在这种情况下,如果方法public
将被消费者调用,那么它是完全合理的; private
如果他们是班级内部人员;和package private
如果它们习惯于在这个模块中的类之间调用,即它是模块的实现细节(如公共调用者所见),但是跨越了几个类。
这在实践中很少使用,因为包装系统对于这种事情并没有那么有用。您必须将给定模块的所有类转储到完全相同的包中,对于任何非平凡的包都会变得有点笨拙。所以这个想法很棒 - 只需要一些“附近”的类就可以访问一个方法,作为一个稍微宽泛的private
- 但是对你如何定义这组类的限制意味着它很少使用/有用。
答案 1 :(得分:14)
package-private的一个好处是你可以使用它来访问你认为是单元测试类私有的方法。当然,缺点是包中的其他类可以在它们真的不应该调用时调用它。
答案 2 :(得分:4)
除了封装之外,使用package-private类的一个主要优点是它们不会出现在项目的javadoc中。因此,如果您使用一些没有其他用途的帮助程序类,但是为了帮助您的公共类执行客户需要的操作,那么将它们打包为私有是有意义的,因为您希望为库的用户保持尽可能简单。
例如,您可以查看我开发的库。 javadoc只包含5个接口和12个类,尽管source code还有更多。但隐藏的主要是内部层,它们不为客户端提供任何附加值(通常隐藏所有抽象基类)。
JDK中也有很多例子。
答案 3 :(得分:2)
关于“为什么会是默认值”的问题,在这种情况下,“默认”一词仅表示缺少另一个限定词。我猜他们本可以发明另一个关键词(已经采用“包”),但他们没有。
在现实世界中,我使用默认访问实用程序类和抽象类,我不希望人们调用或以其他方式使用其他包。假设您有一个接口和两个具体实现,它们从一些抽象类扩展而来。您将两个具体类声明为final,因为您不一定希望人们将它们子类化(请参阅Effective Java)。出于同样的原因,你也不希望人们在你的抽象类中闲逛。如果您对抽象类使用默认访问权限,那么只有当他们将类放在您的包中时,人们才会看到它。它不是防弹,但我认为它是默认访问的合理使用/说明。也就是说,它不会阻止细节作为私人泄露,即不保证任何东西,这意味着它不是一个特别有用的惯例。
你没有经常使用它的另一个原因是人们倾向于从javadocs中排除具有默认访问权限的类。
答案 4 :(得分:2)
包私有访问级别比protected
更具限制性:只需对类进行子类化,仍可访问受保护的属性和方法。 受保护的成员是(或可能)用于继承而package-private成员不是。
通常使用包私有成员,因此包中的多表类可以访问特定于实现的属性或(实用程序)方法。
这方面的好例子是String
的包私有构造函数和StringBuilder.value
char数组:
/*
* Package private constructor which shares value array for speed.
* this constructor is always expected to be called with share==true.
* a separate constructor is needed because we already have a public
* String(char[]) constructor that makes a copy of the given char[].
*/
String(char[] value, boolean share) {
// assert share : "unshared not supported";
this.value = value;
}
因此java.lang
包中的类可以有效地创建新的Strings
,如果内容已经存在char[]
而不影响安全性。你无法从你的应用程序中执行此操作,因为如果可以的话,您将可以访问(引用)String
的内部char数组,该数组是不可变的(反射不计算!)。
在StringBuilder
(或更确切地说是AbstractStringBuilder
中,实现来自)包含当前值char[] value
的char数组和此char[] getValue()
的访问器方法也是包 - 私有所以String
contentEquals(StringBuffer sb)
和contentEquals(CharSequence cs)
这样的各种实用方法可以利用它来提高效率和更快的比较,而不会将内部字符数组暴露给"世界"。
答案 5 :(得分:1)
1 - 取决于架构 - 一般如果你只为自己和小项目编写代码,你可能不会使用它。在较大的项目中,确保您可以控制某些方法的调用位置和方式可能会有所帮助。
2 - 默认(即不是公共/受保护/私有)与私有不同 - 它是第4个州。见Java Access Control
3 - 当您编写不希望第三方依赖于您如何实现底层代码的库时,它可以使生活更轻松 - 您只需将API本身公开。
答案 6 :(得分:0)
请注意,当您谈论课程时,您只有两个选择:
“私人阶级”的概念毫无意义。 (为什么要创建一个没有在任何地方使用的类?!)
因此,如果您有一个不需要向API用户公开的中间操作的类,您应该将其声明为“包私有”
此外,当您在同一源文件中定义许多类时,只允许一个类是公共的(其名称与.java文件名匹配)。如果在同一个文件中定义了任何其他类,则它必须是“package private”。
答案 7 :(得分:-1)
“Package Private”当你有多个包时使用它,这意味着,同一个包中的其他类可以访问该类或类成员为“public”,其他包中的类无法访问,它就像“像他们一样私有” 。“