java java中包级保护有什么用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/403583/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the use of package level protection in java?
提问by krosenvold
I know how package level protection in java works. I reada lot of code (including lots of open source stuff) and no-one seem to be using it. The whole protection level seems slightly faulty to me (I'd have c#'s internal any day of the week).
我知道 java 中的包级保护是如何工作的。我读了很多代码(包括很多开源的东西),但似乎没有人在使用它。整个保护级别对我来说似乎有点错误(我一周中的任何一天都有 c# 的内部)。
Are there any legit real-world use-cases that are in common use ?
是否有任何合法的、普遍使用的现实世界用例?
Edit: A little too late after asking this question I realized I'd forgotten to exclude the "standard" pattern of package protected implementation classes, possibly providing implementations of public interfaces. Everyone uses those, as has been noted several times in the replies. I still think there are a large number of nice replies to this question.
编辑:问这个问题后有点太晚了,我意识到我忘记排除包保护实现类的“标准”模式,可能提供公共接口的实现。每个人都使用这些,正如在回复中多次指出的那样。我仍然认为这个问题有很多很好的回答。
回答by Alex Miller
There are two good uses for package level visibility (in my experience):
包级可见性有两个很好的用途(以我的经验):
1) Defining "internal" classes in a public API. Commonly you would define your interfaces and core factories as public and the "internal" implementations as package level. Then the public factories can construct the package level implementation classes and return them as instances of the public interfaces. This nicely allows users to only access the stuff they should.
1) 在公共 API 中定义“内部”类。通常,您会将接口和核心工厂定义为公共的,将“内部”实现定义为包级别。然后公共工厂可以构造包级实现类并将它们作为公共接口的实例返回。这很好地允许用户只访问他们应该访问的内容。
The downside is that you have to have all this stuff in the same package, which almost never is a good idea for any reasonably-sized API. JSR 294/modules/Project Jigsawin Java 7 will hopefully provide an alternative by specifying a new visibility modifier (module) that can be used to access classes within a module across packages without making them visible outside the module. You can find an example of how this would work in this article.
缺点是你必须将所有这些东西放在同一个包中,这对于任何合理大小的 API 来说几乎从来都不是一个好主意。 JSR 294/modules/ Java 7 中的Project Jigsaw有望通过指定一个新的可见性修饰符 ( module) 来提供替代方案,该修饰符可用于跨包访问模块内的类,而无需使它们在模块外可见。您可以在本文中找到有关如何工作的示例。
2) Unit testing is the other common use case. Frequently you'll see a src tree and a test tree and stuff that would otherwise be private is instead package level so that unit tests in the same (parallel) package are able to access otherwise hidden methods to check or manipulate state.
2) 单元测试是另一个常见的用例。经常你会看到一个 src 树和一个测试树以及本来是私有的东西是包级别的,这样同一个(并行)包中的单元测试就能够访问其他隐藏的方法来检查或操作状态。
回答by Johannes Schaub - litb
Are you talking about package-private protection in Java? That's the protection that is in effect by default for class members. It's useful occasionally if you got classes that interact intimately in a way that requires additional information or methods to be visible.
您是在谈论 Java 中的包私有保护吗?这是默认情况下对类成员有效的保护。如果您的类以需要附加信息或方法可见的方式进行密切交互,那么它偶尔会很有用。
Say you have a Sink class, and several classes can write to that. The Sink has a public method that accepts basic data-types, and a package private method that accepts raw byte arrays. You don't want to make that method public, because you consider it too low-level for its users, but you want to make your other classes (in the package of the Sink) writing to that Sink use it. So you make the method accepting the byte array package private, and classes of your package such as ByteStreamSource could use it. Now, your protection looks like this:
假设您有一个 Sink 类,并且有几个类可以写入该类。Sink 有一个接受基本数据类型的公共方法和一个接受原始字节数组的包私有方法。您不想将该方法公开,因为您认为它对其用户来说太低级了,但是您想让写入该 Sink 的其他类(在 Sink 的包中)使用它。因此,您将接受字节数组包的方法设为私有,并且您的包的类(例如 ByteStreamSource)可以使用它。现在,您的保护看起来像这样:
User Code using the package User
------ | -----------------------------|----- package public Interface
| |
Sink <- package priv. iface -> Sources
The package private interface is orthogonal to the public interface established by the public methods. Package private'ness increases encapsulation, because it encourages you notto make public what shouldn't be public. It's similar to the friendkeyword in C++ and the internalkeyword in C#.
包私有接口与公共方法建立的公共接口正交。包私有性增加了封装性,因为它鼓励您不要公开不应该公开的内容。它类似于friendC++ 中的internal关键字和 C# 中的关键字。
回答by Michael Myers
It can be used for implementation classes, for one thing. For example, EnumSetis an abstract class, and no implementing classes are shown in the docs. Why? Because there are two implementing classes--one for enums with 64 or fewer elements, and one for 65 or more--and you don't really need to know which one you're using. In fact, you don't even need to know that there's more than one implementation. In fact, you don't even need to know that EnumSetis abstract--you just need to know that you can call one of the static methods and get a Setback.
一方面,它可以用于实现类。例如,EnumSet是一个抽象类,文档中没有显示任何实现类。为什么?因为有两个实现类——一个用于具有 64 个或更少元素的枚举,另一个用于 65 个或更多元素——并且您实际上不需要知道正在使用哪一个。事实上,您甚至不需要知道有不止一种实现。事实上,您甚至不需要知道它EnumSet是抽象的——您只需要知道您可以调用其中一个静态方法并Set返回。
In this case, private internal classes might have sufficed (although unwieldy, especially for large classes). But sometimes other classes in a package would need access to such implementation details. protectedcould work, but then they would be open to subclasses also.
在这种情况下,私有内部类可能就足够了(虽然笨拙,尤其是对于大型类)。但有时包中的其他类需要访问此类实现细节。protected可以工作,但他们也会对子类开放。
In short, it covers an area of encapsulation that is not handled by the other three levels of protection.
简而言之,它涵盖了其他三个保护级别未处理的封装区域。
回答by Uri
I think that in principle package level protection makes a lot of sense. It allows you to create something close to a module (a package) but only expose the core classes.
我认为原则上包级保护很有意义。它允许您创建接近模块(包)的东西,但只公开核心类。
For example, many of my projects work with public interfaces and "hidden" classes that implement them. Users use factories, and receive a reference to the interface which corresponds to a "hidden" concrete implementation. With package protection I should be, in theory, able to only expose the interfaces and the factory.
例如,我的许多项目都使用公共接口和实现它们的“隐藏”类。用户使用工厂,并接收对对应于“隐藏”具体实现的接口的引用。有了包保护,理论上,我应该只能公开接口和工厂。
Unfortunately, because package protection does not apply to subpackages, it doesn't really fit the way that I work. I like using other packages and in particular subpackages for my "internal" stuff (in the same way that Eclipse is organized). As a result, my package cannot access package-level protected things in the subpackage. I do wish that this would be changed one day.
不幸的是,因为包保护不适用于子包,所以它并不适合我的工作方式。我喜欢为我的“内部”内容使用其他包,特别是子包(与 Eclipse 的组织方式相同)。结果,我的包无法访问子包中包级受保护的东西。我确实希望有一天能改变这一点。
回答by Charlie Martin
Default protexction, ie "package" protection means it's private to the package, but can "see" anything that's not private to a class in the package. One use is for helper classes for the package; say you have a class that manages a pooled resource you don't want to make visible, you could put it in a default-protection class. Now it can be used by everything in the package, and it can access any protected internals of the other classes, but it's not part of the visible package to a user.
默认保护,即“包”保护意味着它对包是私有的,但可以“看到”包中任何不是私有类的东西。一种用途是用于包的辅助类;假设您有一个管理您不想使其可见的池化资源的类,您可以将它放在一个默认保护类中。现在它可以被包中的所有东西使用,它可以访问其他类的任何受保护的内部结构,但它不是用户可见包的一部分。
回答by Darron
Another use of default protection in Java is for performance.
Java 中默认保护的另一个用途是性能。
Inner classes are allowed to access private members of their containing class, but this is implemented through obfuscated accessor methods. Before the JIT compiler optimizes this away (or in environments without a JIT such as J2ME) this causes a small performance hit. Declaring the needed methods with default protection eliminates the need for these accessor method calls, but doesn't require making the members fully public.
允许内部类访问其包含类的私有成员,但这是通过混淆访问器方法实现的。在 JIT 编译器对此进行优化之前(或在没有 JIT 的环境中,例如 J2ME),这会导致性能下降。使用默认保护声明所需的方法消除了对这些访问器方法调用的需要,但不需要使成员完全公开。
Keep in mind that this is only important where performance is known to be critical, and where you can't count on the JVM fixing the issue for you. But at least it doesn't really harm readability/maintainability as much as many other micro-optimizations.
请记住,这仅在已知性能至关重要且您不能指望 JVM 为您解决问题的情况下才重要。但至少它并没有像许多其他微优化那样真正损害可读性/可维护性。
回答by Dan Dyer
In my opinion, package-private (default) access for methods and fields is useless. In fact, it's worse than useless, it's harmful since it's typically used to provide access to some member that ought to be private but isn't for reasons of convenience.
在我看来,方法和字段的包私有(默认)访问是无用的。事实上,它比无用更糟糕,它是有害的,因为它通常用于提供对某些应该是私有的成员但不是为了方便起见的成员的访问。
However, package-private classes areuseful. You may want to provide an implementation of an interface using a package-private class. A factory method might be declared to return an object that implements a given interface. In this situation, it is not important to know which class is providing the implementation for the interface. By making the class package-private, it is not part of the public API and therefore can be modified or replaced in future versions.
然而,包私有类是有用的。您可能希望使用包私有类提供接口的实现。可以声明工厂方法以返回实现给定接口的对象。在这种情况下,知道哪个类为接口提供实现并不重要。通过使类包私有,它不是公共 API 的一部分,因此可以在未来版本中修改或替换。
In Oak, the language that later became Java, there were only 3 access levels.
在后来成为 Java 的语言 Oak 中,只有 3 个访问级别。
If I were redesigning Java now, I would get rid of the current default (package-private) and make private the default. A private class would be one that is private within its enclosing scope (the package), which would work exactly how package-private classes work already andbe more consistent with the use of 'private' for members.
如果我现在重新设计 Java,我会去掉当前的默认值 (package-private) 并将私有设置为默认值。私有类将是在其封闭范围(包)内私有的类,这将完全按照包私有类的工作方式工作,并且与成员的“私有”使用更加一致。
回答by Stefan Tannenbaum
The reason why nobody uses package level access it is probably a psychological effect. Every java introduction preaches encapsulation, which is understood as declaring all fields private. Private access is very often too narrow, so a public getter/setter must be added. This pattern is then repeated throughout the whole codebase: private fields and public methods everywhere. Ironically, the pattern subverts encapsulation, as the whole implementation is essentially nailed down by the getter/setter pairs.
之所以没有人使用包级别访问,可能是心理作用。每个java介绍都宣扬封装,理解为将所有字段声明为私有。私有访问通常太窄,因此必须添加公共 getter/setter。然后在整个代码库中重复这种模式:到处都是私有字段和公共方法。具有讽刺意味的是,该模式颠覆了封装,因为整个实现基本上是由 getter/setter 对确定的。
A class is primarily the unit of memory allocation and in many cases that is just too small to provide a meaningful interface to the rest of the program. It is a much better idea to use packages as the unit of encapsulation and focus on giving them well defined public interfaces.
类主要是内存分配的单位,在许多情况下,类太小而无法为程序的其余部分提供有意义的接口。使用包作为封装单元并专注于为它们提供定义良好的公共接口是一个更好的主意。
Superpackages in 1.7 might change the rules of the game.
1.7 中的超级包可能会改变游戏规则。
回答by cletus
I know Java veterans of 5-10+ years who don't realize that protectedimplies package private acess. This alone, for me, makes package private an horrific language feature. Personally I don't think there is any justifiable reason to use package private anyway. Let's consider the use cases:
我认识 5-10 年以上的 Java 老手,他们没有意识到这protected意味着包私有访问。对我来说,仅这一点就使包私有成为一种可怕的语言功能。我个人认为无论如何都没有任何正当理由使用包私有。让我们考虑一下用例:
- Package private classes: use inner classes. Another poster suggested there is a (small) performance penalty for inner classes vs package private classes but, to me, that's not a good reason for bad design. Package private and inner classes I consider to be implementation detailsand, as such, I think it's better to "hide" them as inner classes;
- Package private data members: I can see no reason for these at all; and
- Package private methods: these are pretty much the equivalent of C++ friend methods. C++ friends had one good raison d'etre and that was to externalize operator overloading outside of the class, which allowed the first argument to be something other than the class itself. In Java, there is no such use case, which just leaves doing an end-run around encapsulation and abstraction.
- 封装私有类:使用内部类。另一张海报建议内部类与包私有类存在(小)性能损失,但对我来说,这不是设计糟糕的好理由。封装私有类和内部类我认为是实现细节,因此,我认为最好将它们“隐藏”为内部类;
- 封装私有数据成员:我看不出有这些原因;和
- 封装私有方法:这些方法几乎等同于 C++ 友元方法。C++ 朋友有一个很好的存在理由,那就是在类之外将运算符重载外部化,这允许第一个参数不是类本身。在 Java 中,没有这样的用例,它只是围绕封装和抽象进行最终运行。
Compare this to protected methods, which are entirely justifiable when designing classes for extension. I've seen cases where programmers inadvertentlyuse protected methods in unrelated classes in the same package just because they come up on auto-completion lists.
将此与受保护的方法进行比较,这在设计扩展类时是完全合理的。我见过程序员无意中在同一个包中不相关的类中使用受保护方法的情况,只是因为它们出现在自动完成列表中。
And there is absolutely no way to prevent this.
并且绝对没有办法阻止这种情况。
C# has a better access system in that protected doesn't imply internal access. But I consider this--along with a mutable Date class--to be pretty huge flaws.
C# 有一个更好的访问系统,因为受保护并不意味着内部访问。但我认为这 - 连同一个可变的 Date 类 - 是相当大的缺陷。
回答by Sathish
Mostly for Unit testing where source and test files are in the same package, tests can access the internals of the class without exposing it.
大多数情况下,对于源文件和测试文件在同一个包中的单元测试,测试可以访问类的内部而不暴露它。

