我最近在学习 Java,遇到了package-private
类的概念,如果我们不指定任何内容,这是默认的。但后来我意识到:
我很少看到使用包私有类。这是否有原因,例如,它有严重的缺点,它是多余的,或者只是我没有阅读足够的内容?是否有强烈的论据支持/反对它的使用?
如果它在大多数情况下真的没有用,为什么它会成为默认值?
在现实世界中我们应该在什么情况下使用包私有?即,它什么时候会变得不可替代?
换句话说,默认 package-private 修饰符的主要优点和缺点是什么?
我最近在学习 Java,遇到了package-private
类的概念,如果我们不指定任何内容,这是默认的。但后来我意识到:
我很少看到使用包私有类。这是否有原因,例如,它有严重的缺点,它是多余的,或者只是我没有阅读足够的内容?是否有强烈的论据支持/反对它的使用?
如果它在大多数情况下真的没有用,为什么它会成为默认值?
在现实世界中我们应该在什么情况下使用包私有?即,它什么时候会变得不可替代?
换句话说,默认 package-private 修饰符的主要优点和缺点是什么?
简短的回答是 - 它是一种更广泛的私人形式。
我假设您熟悉 和 之间的区别public
,private
以及为什么private
如果方法和变量仅用于相关类的内部,则创建它们通常是一种好习惯。
好吧,作为对此的扩展 - 如果您正在考虑以模块化方式创建软件,您可能会考虑到您的模块的公共接口,其中将有多个类在它们之间相互协作。public
在这种情况下,如果方法要被消费者调用,那么创建方法是非常有意义的;private
如果他们在班级内部;并且package private
如果它们用于在此模块中的类之间调用,即它是您的模块的实现细节(如公共调用者所见),但跨越多个类。
这在实践中很少使用,因为包系统对这类事情没有那么有用。您必须将给定模块的所有类转储到完全相同的包中,这对于任何不平凡的事情都会变得有点笨拙。所以这个想法很棒 - 让少数“附近”类可以访问一个方法,稍微更宽一些private
- 但是对如何定义该组类的限制意味着它很少使用/有用。
package-private 的一个好处是您可以使用它来访问您认为对单元测试类私有的方法。当然,缺点是包中的其他类可以在它们真的不应该调用它时调用它。
包私有访问级别比protected
:受保护的属性和方法仍然可以通过简单地继承一个类来访问。受保护的成员(或可能)用于继承,而包私有成员则不是。
包私有成员经常被使用,因此包中的多类可以访问特定于实现的属性或(实用程序)方法。
很好的例子是包私有构造函数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
包内的类可以有效地创建新的类,而不会影响安全性。您不能从您的应用程序中执行此操作,因为如果可以,您将可以访问(引用)不可变的内部 char 数组(不计算反射!)。Strings
char[]
String
在StringBuilder
(或更确切地说AbstractStringBuilder
是实现的来源)中,保存当前值的 char 数组char[] value
和对此的访问器方法char[] getValue()
也是包私有的,因此各种String
类似contentEquals(StringBuffer sb)
的实用方法contentEquals(CharSequence cs)
可以利用它来提高效率和更快的比较,而无需将内部 char 数组暴露给世界”。
关于“为什么会是默认”的问题,在这种情况下,“默认”一词只是意味着没有另一个限定词。我猜他们本可以发明另一个关键字(“包裹”已经被采用),但他们没有。
在现实世界中,我对实用程序类和抽象类使用默认访问,我不希望人们从其他包调用或以其他方式使用它们。假设您有一个接口和两个从某个抽象类扩展而来的具体实现。您将两个具体类声明为 final,因为您不一定希望人们继承它们(请参阅 Effective Java)。出于同样的原因,您也不希望人们对您的抽象类胡闹。如果您对抽象类使用默认访问,那么人们只有在将他们的类放在您的包中时才能看到它。这不是防弹的,但我认为这是默认访问的合理使用/说明。也就是说,它并不能防止细节像私人那样泄露,即不保证任何事情,这意味着它'
您没有看到它更频繁地使用的另一个原因是人们倾向于从他们的 javadoc 中排除具有默认访问权限的类。
1 - 取决于架构 - 通常,如果您只是为自己和小型项目编写代码,您可能不会使用它。在较大的项目中,确保您可以控制调用某些方法的位置和方式会很有帮助。
2 - 默认(即不是公共/受保护/私有)与私有不同 - 它是第 4 个状态。请参阅Java 访问控制
3 - 当您编写不希望第三方依赖于您如何实现底层代码的库时,它可以让生活更轻松 - 您只需将 API 本身公开。
当你有多个包时使用“包私有”,这意味着同一个包中的其他类可以作为“公共”访问该类或类成员,其他包中的类不能访问,就像“像它们一样私有”。
请注意,当您谈论课程时,您只有两种选择:
“私人课”的概念毫无意义。(为什么要创建一个在任何地方都不使用的类?!)
因此,如果您有一个不需要向 API 用户公开的中间操作类,您应该将其声明为“包私有”
此外,当您在同一个源文件中定义多个类时,只允许公开一个类(其名称与 .java 文件名匹配)。如果在同一文件中定义了任何其他类,则它必须是“包私有”。