I am learning Java recently, and I came across the notion of package-private
classes, which is the default if we don't specify anything. But then I realized:
I seldom see the use of package-private class. Is there a reason for this, e.g., it has serious drawbacks, it is redundant, or simply I am not reading enough? Are there strong arguments for/against its usage?
If it is really not useful in most cases, why would it be the default?
In what situation should we use package-private in the real world? I.e., when would it become irreplaceable?
In other words, what are the major pros and cons of the default package-private modifier?
Apart from encapsulation, one of the main advantages of using package-private classes is that they do not appear in the javadoc of your project. So if you use some helper classes which have no other use but to help your public classes do something clients need, it makes sense to make them package private as you want to keep things as simple as possible for users of the library.
As an example, you can have a look at a library that I have developed. The javadoc only contains 5 interfaces and 12 classes although the source code has a lot more. But what is hidden is mostly internal layers that provide no added-value for a client (typically all the abstract base classes are hidden).
There are also many examples in the JDK.
Please notice that when you are speaking about classes you have only two options:
The concept of "private class" is meaningless. (Why to make a class that is not used anywhere?!)
So if you have a class for intermediate operations that needn't to be exposed to API users you are supposed to declare it as "package private"
Also when you define many classes in the same source file, only one class is allowed to be public (its name matched the .java file name). If any other class is defined in the same file it must be "package private".
The short answer is - it's a slightly wider form of private.
I'll assume that you're familiar with the distinction between
public
andprivate
, and why it's generally good practice to make methods and variablesprivate
if they're going to be used solely internally to the class in question.Well, as an extension to that - if you're thinking about creating your software in a modular way, you might think about a public interface to your module, which will have multiple classes inside it collaborating between themselves. In this context it makes perfect sense to make methods
public
if they're going to be called by consumers;private
if they're internal to a class; andpackage private
if they're used to call between classes in this module, i.e. it's an implementation detail of your module (as seen by public callers) but spans several classes.This is seldom used in practice, because the package system turns out to not be so useful for this sort of thing. You'd have to dump all of the classes for a given module into exactly the same package, which for anything non-trivial is going to get a bit unwieldy. So the idea is great - make a method accessible to just a handful of "nearby" classes, as a slightly wider
private
- but the restrictions on how you define that set of classes means it's rarely used/useful.1 - Depends on the architecture -Generally if you are writing code just for yourself and on small projects you probably wouldn't use it. In larger projects it can be helpful to ensure that you can control where and how certain methods are called.
2 - Default (I.e. not public/protected/private) is not the same as private - its a 4th state. See Java Access Control
3 - It can make life easier when you're writing libraries that you don't want third parties relying on how you are implementing the underlying code - you just make the API itself public.
Regarding the question of "why would it be the default,", in this context, the term "default" just means the absence of another qualifier. I guess they could have invented another keyword ("package" was already taken), but they didn't.
In the real world, I use default access for utility classes and abstract classes that I don't want people to call or otherwise use from other packages. Let's say you have an interface and two concrete implementations that extend from some abstract class. You declare your two concrete classes as final because you don't necessarily want people to subclass them (see Effective Java). You also don't want people to monkey around with your abstract class for the same reason. If you use default access for the abstract class, then people only see it if they put their class in your package. It's not bullet proof, but I think it's a reasonable use/illustration of default access. That said, the fact that it does not prevent the details from leaking as private would, i.e. doesn't guarantee anything, means that it's not a particularly useful convention.
Another reason why you haven't see it used more often is that people tend to exclude classes with default access from their javadocs.
The package-private access level is more restrictive than
protected
: protected attributes and methods can still be accessed by simply subclassing a class. Protected members are (or may be) intended for inheritance while package-private members are not.Package-private members are often used so multilpe classes inside a package can access implementation-specific attributes or (utility) methods.
Good examples to this are the package-private constructor of
String
and theStringBuilder.value
char array:So classes inside the
java.lang
package can efficiently create newStrings
if the content is already present in achar[]
without compromising security. You cannot do this from your application because if you could, you would have access (reference) to the internal char array of aString
which is immutable (reflection not counted!).In
StringBuilder
(or ratherAbstractStringBuilder
where the implementation comes from) the char array holding the current valuechar[] value
and an accessor method to thischar[] getValue()
are also package-private so various utility methods ofString
likecontentEquals(StringBuffer sb)
andcontentEquals(CharSequence cs)
can utilize this for efficiency and faster comparisons without exposing the internal char array to the "world".