代码之家  ›  专栏  ›  技术社区  ›  krosenvold

java中包级保护的用途是什么?

  •  22
  • krosenvold  · 技术社区  · 16 年前

    我知道java中的包级保护是如何工作的。一、 阅读 有很多代码(包括很多开源的东西),但似乎没有人在使用它。整个保护级别对我来说似乎有点问题(我一周中的任何一天都有c#的内部)。

    是否有任何在现实世界中普遍使用的合法用例?

    编辑:问这个问题有点晚了,我意识到我忘了排除包保护实现类的“标准”模式,可能提供公共接口的实现。正如在回复中多次指出的那样,每个人都在使用这些。我仍然认为这个问题有很多很好的答案。

    15 回复  |  直到 16 年前
        1
  •  33
  •   Alex Miller    16 年前

    根据我的经验,包级可见性有两个很好的用途:

    1) 在公共API中定义“内部”类。通常,您会将接口和核心工厂定义为公共,将“内部”实现定义为包级。然后,公共工厂可以构建包级实现类,并将其作为公共接口的实例返回。这很好地允许用户只访问他们应该访问的内容。

    缺点是必须将所有这些东西放在同一个包中,这对于任何大小合理的API来说几乎都不是一个好主意。 JSR 294 /模块/ Project Jigsaw 在Java 7中,通过指定一个新的可见性修饰符,有望提供一种替代方案( module )它可用于跨包访问模块内的类,而不会使它们在模块外可见。你可以找到一个例子来说明这是如何工作的 in this article .

    2) 单元测试是另一个常见用例。您经常会看到一个src树和一个测试树,否则这些树将是私有的,而不是包级的,这样同一(并行)包中的单元测试就能够访问其他隐藏的方法来检查或操纵状态。

        2
  •  12
  •   BenMorel Manish Pradhan    11 年前

    你是在谈论Java中的包私有保护吗?这是默认情况下对类成员生效的保护。如果你的类以一种需要额外信息或方法才能可见的方式密切交互,那么它偶尔会很有用。

    假设你有一个Sink类,有几个类可以写入该类。Sink有一个接受基本数据类型的公共方法和一个接受原始字节数组的包私有方法。你不想将该方法设为公共,因为你认为它对用户来说太低级了,但你想让写入该接收器的其他类(在接收器的包中)使用它。因此,你将接受字节数组包的方法设为私有,并且包中的类(如ByteStreamSource)可以使用它。现在,你的保护看起来像这样:

         User   Code using the package   User
    ------ | -----------------------------|----- package public Interface
           |                              |
        Sink <-   package priv. iface  -> Sources
    

    包私有接口与公共方法建立的公共接口正交。包私有性增加了封装,因为它鼓励你 公开不应该公开的东西。它类似于 friend C++中的关键字和 internal C#中的关键字。

        3
  •  8
  •   Michael Myers KitsuneYMG    16 年前

    首先,它可以用于实现类。例如, EnumSet 是一个抽象类,文档中没有显示实现类。为什么?因为有两个实现类——一个用于64个或更少元素的枚举,一个用于65个或更多元素的枚举——你真的不需要知道你在使用哪个。事实上,你甚至不需要知道有不止一个实现。事实上,你甚至不需要知道 枚举集 是抽象的——你只需要知道你可以调用其中一个静态方法并获得 Set < 返回

    在这种情况下,私有内部类可能就足够了(尽管笨拙,尤其是对于大型类)。但有时包中的其他类需要访问这些实现细节。 protected 可以工作,但这样它们也会对子类开放。

    简而言之,它覆盖了其他三个保护级别无法处理的封装区域。

        4
  •  5
  •   Uri    16 年前

    我认为原则上,包级保护很有意义。它允许您创建接近模块(包)的东西,但只公开核心类。

    例如,我的许多项目都使用公共接口和实现它们的“隐藏”类。用户使用工厂,并收到对接口的引用,该接口对应于“隐藏”的具体实现。理论上,有了包保护,我应该只能暴露接口和工厂。

    不幸的是,因为包保护不适用于子包,所以它并不适合我的工作方式。我喜欢使用其他包,特别是子包来处理我的“内部”内容(与Eclipse的组织方式相同)。因此,我的包无法访问子包中受包级保护的内容。我真希望有一天能改变这一点。

        5
  •  3
  •   Charlie Martin    16 年前

    默认的protexction,即“包”保护意味着它对包是私有的,但可以“看到”包中类不私有的任何东西。一个用途是用于包的辅助类;假设你有一个管理池资源的类,你不想让它可见,你可以把它放在默认的保护类中。现在,它可以被包中的所有东西使用,并且可以访问其他类的任何受保护的内部,但它不是用户可见包的一部分。

        6
  •  3
  •   L. Cornelius Dol    16 年前

    Java中默认保护的另一个用途是性能。

    允许内部类访问其包含类的私有成员,但这是通过混淆的访问器方法实现的。在JIT编译器优化之前(或在没有JIT的环境中,如J2ME),这会导致性能下降。使用默认保护声明所需的方法消除了对这些访问器方法调用的需要,但不需要使成员完全公开。

    请记住,只有在已知性能至关重要的情况下,以及在不能指望JVM为您解决问题的情况下才重要。但至少它不会像许多其他微优化那样真正损害可读性/可维护性。

        7
  •  2
  •   Dan Dyer    16 年前

    在我看来,方法和字段的包私有(默认)访问是无用的。事实上,它比无用更糟糕,它是有害的,因为它通常用于为一些应该是私有的但不是出于方便的原因的成员提供访问权限。

    但是,打包私有类 有用的。您可能希望使用包私有类提供接口的实现。可以声明一个工厂方法来返回实现给定接口的对象。在这种情况下,知道哪个类为接口提供实现并不重要。通过使类package-private,它不是公共API的一部分,因此可以在未来的版本中进行修改或替换。

    在后来成为Java的Oak语言中, there were only 3 access levels .

    如果我现在重新设计Java,我会去掉当前的默认值(包私有),将私有设置为默认值。私有类将是在其封闭范围(包)内私有的类,这将与包私有类的工作方式完全相同 与会员使用“private”更为一致。

        8
  •  2
  •   Stefan Tannenbaum    16 年前

    没有人使用包级访问的原因可能是心理影响。每个java介绍都宣扬封装,这被理解为声明所有字段都是私有的。私有访问通常太窄,因此必须添加公共getter/setter。然后,这种模式在整个代码库中重复:到处都是私有字段和公共方法。具有讽刺意味的是,该模式颠覆了封装,因为整个实现基本上是由getter/setter对固定的。

    类主要是内存分配的单位,在许多情况下,它太小,无法为程序的其余部分提供有意义的接口。使用包作为封装单元并专注于为它们提供定义良好的公共接口是一个更好的主意。

    1.7版本的超级包装可能会改变游戏规则。

        9
  •  1
  •   Milhous    16 年前

    我有一些需要相互访问的对象。在包内,它们可以调用这些受保护的方法,但当有人试图访问这些受保护方法时,它们将被禁止。

    在我看来,这是一种基本的保护机制,保护层次结构将是一个很好的功能。

        10
  •  1
  •   mfx    16 年前

    如今,包通常用于对“软件组件”进行建模,即包是一组以某种方式相关的类。由于“公共”方法定义了软件组件的外部接口,而“私有”方法/成员是类的实现细节,因此默认的“包”可见性相当于组件内部方法。

    一个类比可能是C++中的“friend”方法。

        11
  •  1
  •   cletus    16 年前

    我认识5-10岁以上的Java老手,他们没有意识到这一点 protected 意味着包私有访问。对我来说,仅凭这一点,就让包私有化成为一个可怕的语言功能。就我个人而言,我认为无论如何都没有任何合理的理由使用包私有。让我们考虑一下用例:

    • 打包私有类:使用内部类。另一张海报显示,内部类与包私有类相比会有(小)性能损失,但对我来说,这不是设计糟糕的好理由。打包我认为的私人和内部课程 实现细节 因此,我认为最好将它们“隐藏”为内部类;
    • 包私有数据成员:我看不出有什么理由;和
    • 包私有方法:这些方法几乎相当于C++的朋友方法。C++朋友有一个很好的理由,那就是将运算符重载外部化到类之外,这使得第一个参数可以是类本身以外的东西。在Java中,没有这样的用例,只剩下围绕封装和抽象进行最终运行。

    将其与受保护的方法进行比较,在为扩展设计类时,这些方法是完全合理的。我见过程序员的案例 无意地 在同一包中不相关的类中使用受保护的方法,仅仅因为它们出现在自动补全列表中。

    而且绝对没有办法阻止这种情况。

    C#有一个更好的访问系统,因为受保护并不意味着内部访问。但我认为这——以及一个可变的Date类——是相当大的缺陷。

        12
  •  1
  •   Sathish    16 年前

    主要用于源文件和测试文件位于同一包中的单元测试,测试可以访问类的内部,而无需公开它。

        13
  •  1
  •   Howard Swope    13 年前

    我目前正在脑海中讨论许多这些问题,这是一个很好的讨论。我一直在选择让所有私有的东西都像它们应该的那样私有,但后来我正在编写大量的反射到单元测试私有范围的代码。我认为这是纯面向对象的方法。然而,我发现可以密封一个jar文件,将包作用域限制在模块(jar)内部。在我看来,这使得包装范围更加可口。我可能愿意打破良好的封装,以换取将我的单元测试代码减少到原来的一小部分。我的想法是,如果有人在同一个库和同一个包中工作,他们将与代码库足够亲密,在没有合理的设计辩论的情况下,不会从类外访问包作用域成员。这仍然是一个艰难的决定。为这种类型的实例指定一个朋友类类型会很好,这样我的单元测试代码就可以访问我的私有代码,而不会被其他类访问。我刚刚通过maven将jar文件密封在这个项目中:

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <archive>
                        <index>true</index>
                        <manifest>
                            <addClasspath>true</addClasspath>
                        </manifest>
                        <manifestEntries>
                            <sealed>true</sealed>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>
    

    现在,我正在讨论在我的单元测试中提取一堆反射代码。

    我仍然处于辩论的边缘。包的作用域非常开放,特别是当你有很多开发人员在代码库中来回走动时。

        14
  •  0
  •   Bill K    16 年前

    一般来说,默认/包保护可用于使“公共”类和变量受到更多限制。

    如果你是一名优秀的程序员,你只需将类中的一些方法标记为公共,同时尽可能多地保持私有,就可以从类中导出这些方法。

    包保护允许您仅从包中导出少数类,其余类保持私有。

    从理论上讲,这是一个好主意,但在实践中,你几乎从未见过它。

        15
  •  0
  •   Ed Kirwan Ed Kirwan    16 年前

    “我知道java中的包级保护是如何工作的……但似乎没有人使用它。”

    他们在用什么?

    他们把所有的课都公开了吗?

    负担原则有两种形式。

    强形式表明,转换实体集合的负担是转换实体数量的函数。弱形式指出,转换实体集合的最大潜在负担是转换实体的最大潜在数量的函数。

    国际标准化组织将封装定义为对象中包含的信息只能通过对象支持的接口处的交互访问的属性。

    在更高的抽象层次上,程序单元也可以封装在子系统中,因此子系统中包含的信息只能通过子系统中的公共程序单元访问。

    创建或修改任何软件系统的负担取决于创建或修改的程序单元的数量。

    依赖于特定修改后的程序单元的程序单元比不依赖于修改后程序单元的编程单元更有可能受到影响。

    修改后的程序单元可以施加的最大潜在负担是依赖它的所有程序单元的影响。

    因此,减少对修改后的程序单元的依赖性可以降低其更新影响其他程序单元的可能性,从而减少该程序单元可能施加的最大潜在负担。

    因此,减少系统中所有程序单元之间的最大潜在依赖数量可以降低对特定程序单元的影响导致其他程序单元更新的可能性,从而减少所有更新的最大潜在负担。

    封装理论展示了如何使用封装来减少所有程序单元之间的最大潜在依赖数量。

    因此,封装理论展示了如何使用封装来减轻负担原则的弱形式。

    在Java中,将类包私有化是减少系统中最大潜在依赖关系数量的关键机制之一,从而减少对该系统进行任何软件修改的最大可能负担。

    然而,你提到这在你阅读的代码中没有使用。

    听起来不错。..奇怪。