Java中包私有类的优缺点?

时间:2011-06-24 16:03:51

标签: java class default modifier package-private

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

  1. 我很少看到使用package-private类。是否有这样的理由,例如,它有严重的缺点,它是多余的,或者只是我阅读不够?是否有强烈支持/反对其使用的论据?

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

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

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

8 个答案:

答案 0 :(得分:51)

简短的回答是 - 这是一种稍微宽泛的私人形式。

我假设您熟悉publicprivate之间的区别,以及为什么制作方法和变量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)

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

  1. 公共课
  2. 包私有类
  3. “私人阶级”的概念毫无意义。 (为什么要创建一个没有在任何地方使用的类?!)

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

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

答案 7 :(得分:-1)

“Package Private”当你有多个包时使用它,这意味着,同一个包中的其他类可以访问该类或类成员为“public”,其他包中的类无法访问,它就像“像他们一样私有” 。“