Fairly new to Java, but I'm wondering why package access is considered "more restrictive" than subclass access. That is, every access modifier which provides subclasses with access to a member also provides the whole package with access, and there are modifiers whic provide package access but not subclass access.
Isn't this totally backwards? Let's say I have a class ControlledInstantiation in some package. If I have another class AlsoControlledInstantiation extends ControlledInstantiation, I am unable to call the constructor of ControlledInstantiation unless I set it to protected or public. And if I set it to protected, now any other class in the package can instantiate it as often as it likes. So something which is obliged to be substitutable for its superclass (and, syntactically, is) gets the same or less access to the superclass than something which serves a distinct but related function. It's like telling your child he can't play with your wallet because you wouldn't let your neighbours do it and then letting your neighbours sleep in your house because your kid does.
So I guess I'm asking, what motivated this decision, and how can I get around it?
It may seem backwards at first, but the idea is that a Java package should contain a set of comparatively cohesive classes which are semantically related, and this is reflected in the default package modifier. Then the logic is that if you want to go one step further and allow subclasses from any package to view your members, you can declare them protected. Does it make sense to you that subclasses from foreign packages should be less trusted than any class (whether a subclass or not) from your own package?
Java did in fact once have a private protected modifier which would achieve what you're after, but it was removed, I imagine, because it confused people. I'm not really sure how you could achieve this without relegating each class/subclass pair to its own package. But that's a messy solution which goes against Java's principles and it wouldn't work for inheritance hierarchies of more than two classes anyway.
You are right, this fact is a little bit confusing.
Here are the workarounds I can suggest.
Your example with protected constructor is more relevant for methods. In some cases you can avoid access to protected constructor by package member that are not the subclasses of current class if you mark class as abstract.
If you really wish to avoid access to protected method by package members you can solve this problem at least at runtime using Throwable.getStacktrace():
if(!getClass().isAssignableFrom(
Class.forName(new Throwable().getStackTrace()[1].getClassName()))) {
throw new IllegalAccessException(
"This method can be accessed by subclass only");
}
You can seal a package. See the JAR File Specification.