Java中包私有类的优缺点?

我最近正在学习Java,并且遇到了package-private类的概念,如果我们没有指定任何东西,这是默认的。 但后来我意识到:

  1. 我很less看到使用包私有类。 这是有原因的,例如它有严重的缺点,是多余的,或者说我读得不够好? 有没有有力的论据来反对它的使用?

  2. 如果在大多数情况下它确实没有用,为什么它是默认的?

  3. 在什么情况下我们应该在现实世界中使用package-private? 也就是说,它什么时候变得不可替代?

换句话说,默认的package-private修饰符的主要优点和缺点是什么?

简短的答案是 – 这是一个稍微宽泛的私人forms。

我假设你熟悉publicprivate之间的区别,为什么一般来说,如果将这些方法和variables单独用于所讨论的课程,这些方法和variables就是private

那么,作为一个扩展 – 如果你正在考虑以模块化的方式创build你的软件,你可能会考虑一个公共接口到你的模块 ,它将在它们之间有多个类进行协作。 在这种情况下,如果方法被消费者打电话,使得方法public是非常有意义的。 private如果他们是一个class级的内部; 如果它们用于在这个模块中的类之间进行调用,也就是说它是你的模块的一个实现细节(如公共调用者所看到的那样),但是它包含了一些私有的类。

这在实践中很less使用,因为这种包装系统对于这种事情不是那么有用。 你必须将给定模块的所有类转储到完全相同的包中,对于任何不重要的东西都会变得笨重。 所以这个想法很好 – 只需要less量的“附近”类就可以访问一个方法,就像一个稍微宽一点的private ,但是如何定义这个类的限制意味着它很less被使用/有用。

package-private的一个好处是你可以使用它来访问你认为私有的unit testing类的方法。 当然不利的一面是,这个软件包中的其他类可以在不应该的时候调用它。

关于“为什么会是违约”的问题,在这种情况下,“违约”一词就意味着没有另一个限定词。 我想他们可能已经发明了另一个关键字(“包”已经被采纳),但他们没有。

在现实世界中,我使用默认访问实用程序类和抽象类,我不希望人们调用或从其他包使用。 假设你有一个接口和两个具体的实现,从一些抽象类扩展。 你声明你的两个具体类是最终的,因为你不一定需要人们inheritance它们(见Effective Java)。 你也不希望人们出于同样的原因在你的抽象类中徘徊。 如果您对抽象类使用默认访问权限,那么只有在您的包中放入类时才会看到它。 这不是防弹的,但我认为这是对默认访问的合理使用/说明。 这就是说,它不能防止细节泄漏,即不保证任何东西,这意味着它不是一个特别有用的惯例。

为什么你没有看到它更经常使用的另一个原因是人们倾向于从javadocs中排除具有默认访问权限的类。

除封装之外,使用包私有类的主要优点之一是它们不出现在项目的javadoc中。 所以,如果你使用了一些帮助器类,除了帮助你的公共类做一些客户需要的东西,把它们打包为私有是有意义的,因为你希望为图书馆的用户尽可能简单地保持一些东西。

作为一个例子,你可以看看我开发的一个库。 javadoc只包含5个接口和12个类,尽pipe源代码有很多。 但是隐藏的内容大多是内部层,它们不能为客户端提供附加价值(通常所有的抽象基类都是隐藏的)。

JDK中也有很多例子。

1 – 取决于体系结构 – 一般来说,如果您只是为自己编写代码,而在小型项目中,您可能不会使用它。 在较大的项目中,确保您可以控制某些方法在何处以及如何被调用是有帮助的。

2 – 默认(即不公开/保护/私人)不是私有的 – 它是第四国家。 请参阅Java访问控制

3 – 当你编写图书馆时,它可以让生活变得更轻松,你不希望第三方依赖于你如何实现底层代码 – 你只需要公开API。

请注意,当你讲课时,你只有两个select:

  1. 公开课
  2. 打包私人课程

“私人阶级”的概念是没有意义的。 (为什么要做一个没有用过的类?!)

所以如果你有一个中间操作类,不需要暴露给API用户,你应该把它声明为“package private”

同样,当你在同一个源文件中定义很多类时,只允许一个类是公共的(它的名字与.java文件名相匹配)。 如果在同一文件中定义了任何其他类,则必须是“私有包”。

包 – 私有访问级别比protected保护的限制性更强:受保护的属性和方法仍然可以通过简单inheritance一个类来访问。 受保护的成员是(或可能)意图inheritance,而包私有成员则不是。

包私有成员经常被使用,因此包内的多重类可以访问特定实现的属性或(实用)方法。

比较好的例子是StringStringBuilder.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; } 

因此,如果内容已经存在于char[]而不会影响安全性,那么java.lang包内的类可以高效地创build新的Strings 。 你不能从你的应用程序这样做,因为如果可以的话,你将有权访问(引用)一个String的内部char数组是不可变的(reflection不计数!)。

StringBuilder (或者说实现来自AbstractStringBuilder ),持有当前值char[] value的char数组和char[] getValue()一个存取方法也是package-private,所以String各种实用方法如contentEquals(StringBuffer sb)contentEquals(CharSequence cs)可以利用这个效率和更快的比较而不暴露内部字符数组到“世界”。

当你有几个包时使用“Package Private”,也就是说,同一个包中的其他类可以访问该类或类成员为“public”,而其他包中的类不能访问,就像“private like”一样。