71

我最近在学习 Java,遇到了package-private类的概念,如果我们不指定任何内容,这是默认的。但后来我意识到:

  1. 我很少看到使用包私有类。这是否有原因,例如,它有严重的缺点,它是多余的,或者只是我没有阅读足够的内容?是否有强烈的论据支持/反对它的使用?

  2. 如果它在大多数情况下真的没有用,为什么它会成为默认值?

  3. 在现实世界中我们应该在什么情况下使用包私有?即,它什么时候会变得不可替代?

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

4

8 回答 8

60

简短的回答是 - 它是一种更广泛的私人形式。

我假设您熟悉 和 之间的区别publicprivate以及为什么private如果方法和变量仅用于相关类的内部,则创建它们通常是一种好习惯。

好吧,作为对此的扩展 - 如果您正在考虑以模块化方式创建软件,您可能会考虑到您的模块的公共接口,其中将有多个类在它们之间相互协作。public在这种情况下,如果方法要被消费者调用,那么创建方法是非常有意义的;private如果他们在班级内部;并且package private如果它们用于在此模块中的类之间调用,即它是您的模块的实现细节(如公共调用者所见),但跨越多个类。

这在实践中很少使用,因为包系统对这类事情没有那么有用。您必须将给定模块的所有类转储到完全相同的包中,这对于任何不平凡的事情都会变得有点笨拙。所以这个想法很棒 - 让少数“附近”类可以访问一个方法,稍微更宽一些private- 但是对如何定义该组类的限制意味着它很少使用/有用。

于 2011-06-24T16:20:52.910 回答
17

package-private 的一个好处是您可以使用它来访问您认为对单元测试类私有的方法。当然,缺点是包中的其他类可以在它们真的不应该调用它时调用它。

于 2011-06-24T17:14:17.720 回答
5

除了封装之外,使用包私有类的主要优点之一是它们不会出现在项目的 javadoc 中。因此,如果您使用一些除了帮助您的公共类做客户需要的事情之外没有其他用途的帮助类,那么将它们封装为私有是有意义的,因为您希望使库的用户尽可能简单。

例如,您可以查看我开发的库。javadoc仅包含 5 个接口和 12 个类,尽管源代码还有很多。但是隐藏的主要是内部层,它们没有为客户提供任何附加值(通常所有抽象基类都是隐藏的)。

JDK中也有很多例子。

于 2013-07-01T20:08:09.717 回答
3

包私有访问级别比protected:受保护的属性和方法仍然可以通过简单地继承一个类来访问。受保护的成员(或可能)用于继承,而包私有成员则不是。

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

很好的例子是包私有构造函数StringStringBuilder.valuechar 数组:

/*
* 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 数组(不计算反射!)。Stringschar[]String

StringBuilder(或更确切地说AbstractStringBuilder是实现的来源)中,保存当前值的 char 数组char[] value和对此的访问器方法char[] getValue()也是包私有的,因此各种String类似contentEquals(StringBuffer sb)的实用方法contentEquals(CharSequence cs)可以利用它来提高效率和更快的比较,而无需将内部 char 数组暴露给世界”。

于 2015-02-10T07:05:50.053 回答
2

关于“为什么会是默认”的问题,在这种情况下,“默认”一词只是意味着没有另一个限定词。我猜他们本可以发明另一个关键字(“包裹”已经被采用),但他们没有。

在现实世界中,我对实用程序类和抽象类使用默认访问,我不希望人们从其他包调用或以其他方式使用它们。假设您有一个接口和两个从某个抽象类扩展而来的具体实现。您将两个具体类声明为 final,因为您不一定希望人们继承它们(请参阅 Effective Java)。出于同样的原因,您也不希望人们对您的抽象类胡闹。如果您对抽象类使用默认访问,那么人们只有在将他们的类放在您的包中时才能看到它。这不是防弹的,但我认为这是默认访问的合理使用/说明。也就是说,它并不能防止细节像私人那样泄露,即不保证任何事情,这意味着它'

您没有看到它更频繁地使用的另一个原因是人们倾向于从他们的 javadoc 中排除具有默认访问权限的类。

于 2011-06-24T16:32:36.923 回答
1

1 - 取决于架构 - 通常,如果您只是为自己和小型项目编写代码,您可能不会使用它。在较大的项目中,确保您可以控制调用某些方法的位置和方式会很有帮助。

2 - 默认(即不是公共/受保护/私有)与私有不同 - 它是第 4 个状态。请参阅Java 访问控制

3 - 当您编写不希望第三方依赖于您如何实现底层代码的库时,它可以让生活更轻松 - 您只需将 API 本身公开。

于 2011-06-24T16:08:33.363 回答
-1

当你有多个包时使用“包私有”,这意味着同一个包中的其他类可以作为“公共”访问该类或类成员,其他包中的类不能访问,就像“像它们一样私有”。

于 2011-06-24T17:04:09.450 回答
-1

请注意,当您谈论课程时,您只有两种选择:

  1. 公开课
  2. 封装私有类

“私人课”的概念毫无意义。(为什么要创建一个在任何地方都不使用的类?!)

因此,如果您有一个不需要向 API 用户公开的中间操作类,您应该将其声明为“包私有”

此外,当您在同一个源文件中定义多个类时,只允许公开一个类(其名称与 .java 文件名匹配)。如果在同一文件中定义了任何其他类,则它必须是“包私有”。

于 2013-01-03T15:04:40.040 回答