Which access modifier, in an abstract class, do I have to use for a method, so the subclasses can decide whether it should be public or not? Is it possible to "override" a modifier in Java or not?
public abstract class A {
??? void method();
}
public class B extends A {
@Override
public void method(){
// TODO
}
}
public class C extends B {
@Override
private void method(){
// TODO
}
}
I know that there will be a problem with static binding, if someone calls:
// Will work
A foo = new B()
foo.method();
// Compiler ?
A foo = new C();
foo.method();
But maybe there is another way. How I can achieve that?
Here is a part of the
@Override
contract.The answer is : there isn't any possibility to achieve what you have.
This is not a problem concerning
abstract
classes only but all classes and methods.When overriding methods, you can only change the modifier to a wider one, not vice versa. For example this code would be valid:
However, if you try to narrow down the visibility, you'd get a compile-time error:
For your case, I'd suggest to make
C
not implementingA
, asA
's abstraction implies that there's a non-privatemethod()
:Another option is to make the
method()
implementation inC
throwing a RuntimeException:This is impossible because of the polymorphism. Consider the following. You have the method in class
A
with some access modifier which is notprivate
. Why not private? Because if it was private, then no other class could even know of its existence. So it has to be something else, and that something else must be accessible from somewhere.Now let's suppose that you pass an instance of class
C
to somewhere. But you upcast it toA
beforehand, and so you end up having this code somewhere:One nice example how this got broken is QSaveFile in Qt. Unlike Java, C++ actually allows to lower access privileges. So they did just that, forbidding the
close()
method. What they ended up with is aQIODevice
subclass that is not really aQIODevice
any more. If you pass a pointer toQSaveFile
to some method acceptingQIODevice*
, they can still callclose()
because it's public inQIODevice
. They “fixed” this by makingQSaveFile::close()
(which is private) callabort()
, so if you do something like that, your program immediately crashes. Not a very nice “solution”, but there is no better one. And it's just an example of bad OO design. That's why Java doesn't allow it.Edit
Not that I missed that your class is abstract, but I also missed the fact that
B extends C
, notA
. This way what you want to do is completely impossible. If the method ispublic
in B, it will be public in all subclasses too. The only thing you can do is document that it shouldn't be called and maybe override it to throwUnsupportedOperationException
. But that would lead to the same problems as withQSaveFile
. Remember that users of your class may not even know that it's an instance ofC
so they won't even have a chance to read its documentation.Overall it's just a very bad idea OO-wise. Perhaps you should ask another question about the exact problem you're trying to solve with this hierarchy, and maybe you'll get some decent advises on how to do it properly.
It is possible to relax the restriction, but not to make it more restrictive:
Making the original method
private
won't work either, since such method isn't visible in subclasses and therefore cannot be overriden.I would recommend using
interface
s to selectively expose or hide the method:... then only work with the instances through the interfaces.
What you are asking for is not possible for very good reasons.
The Liskov substitution principle basically says: a class S is a subclass of another class T only then, when you can replace any occurrence of some "T object" with some "S object" - without noticing.
If you would allow that S is reducing a public method to private, then you can't do that any more. Because all of a sudden, that method that could be called while using some T ... isn't available any more to be called on S.
Long story short: inheritance is not something that simply falls out of the sky. It is a property of classes that you as the programmer are responsible for. In other words: inheritance means more than just writing down "class S extends T" in your source code!
THEORY:
You have the determined modifiers order:
When you override the method, you can increase, but not decrease the modifier level. For example,
PRACTICE:
In your case, you cannot turn
???
into some modifier, becauseprivate
is the lowest modifier andprivate
class members are not inherited.