If i have a top level class classA in packageA, and i want to make a classB extend classA, but i want to include classB in packageB, without any other class in packageB being able to have access to classA (so classA cannot be public), wouldnt this mean that classA must be accessible to its own package plus its children that are in other packages, hence shouldnt classA be protected? obviously we can solve this by moving classB to packageA but what if we cannot do for some reason?
alright i guess i have to fill this in too, i tried making classA protected and i got an error.
In basis, what you asked for is not possible. The problem is a semantic/philosophy argument: What does protected
really mean?
Sure, it's defined as: "Only accessible / visible by anything else in the same package, and any subclasses".
However, if I write:
class ClassB extends ClassA {}
where ClassB and ClassA are not in the same package, and ClassA has hypotetically protected
access level, how does the chicken and egg situation work? In order to 'parse and understand' extends ClassA
, we need to be in a valid context (in the same package, or be a subclass), but we aren't in that context quite yet.
We can update the lang spec to decree that for the purposes of understanding any extends
or implements
clauses, that we should act as if we are in the right context for the purposes of protected
. But that is an additional complication.
Hence, instead, the spec erred on the side of caution and simply doesn't allow it.
So, to answer your direct question:
Q: Why can't we we have protected top level class in java?
A: Because the spec says so.
That's it. That's the answer.
I assume you find that answer not very satisfying. But it is the answer.
So let's instead answer your underlying question, which is actually:
Q: I have a class (ClassA
) that I do not want any code outside of ClassA
's package to be able to access - I do not want any code to invoke static methods or read static fields (ClassA.someStaticMethod()
), and I do not want any code to be able to create new instances (new ClassA()
) either. However, I do want code outside of ClassA
's package to write extends ClassA
.
But, unfortunately, the answer there is: That is a bizarre question, and I (and, evidently, the authors of the java language specification) cannot fathom any realistic scenarios where you'd want such an access level.
There is no access level modifier that means: "This method is not accessible to code outside of the class, except for source files who source file name starts with the letter 'Q', those can access it". For the same reason: That's so bizarre the authors didn't foresee any need for it, and therefore, the language doesn't support it.
I suggest you make it public
, and document it accordingly. Alternatively, consider that the only useful things you can do with a class are always focused on members of it. There's nothing useful you can do with, literally:
class ExampleUselessClass {
// the class is completely empty. There is nothing here.
}
Then who cares what the access level of that class is? It's not useful, in any way.
Thus, you can effectively get what you want by making every member within ClassA
protected instead.
If you have:
public class ClassA {
protected static final String SOME_CONSTANT = "Hello";
protected int someField = 5;
protected ClassA() {
// our constructor
}
protected void foo() {
// some method
}
}
Then explain to me what code in other packages can do, that you do not want it to do? Think it through. Other code can't write new ClassA()
(unless they extends ClassA
), they can't write ClassA.SOME_CONSTANT
, they can't write someInstanceOfClassB.foo()
unless you override foo()
in ClassB
. What's left, other than academic pointless cases, such as, say:
Class<?> classRef = ClassA.class;
restricted access levels (private
, package private, protected
) are API access tools: They let you mark parts of your API as: "Hey, I do not feel like documenting precisely what these methods do, and I reserve the right to modify this stuff in backwards incompatible ways in point releases.".
It doesn't mean anything further. access levels aren't security tools. Code that wants to 'access private stuff' can do so trivially (using reflection, or just hacking the class file, that's trivial to do). That's not the point of private
and friends. Whatever's left isn't API related and therefore isn't relevant. There's no purpose to denying other code from writing ClassA.class
or otherwise referring to the existence of ClassA
itself (not to anything it can do, i.e. any of its fields/methods/inner types).