I have a following class hierarchy:
interface Repository
// This class contains some common stuff for LocalRepository and RemoteRepository. I'm never going to use this class outside this file, so I make it private
private abstract class BasicRepositoryImpl
// these classes are designed to be instantiated in other files
class LocalRepository : BasicRepositoryImpl(), Repository // error
class RemoteRepository : BasicRepositoryImpl(), Repository // error
But I get the following error:
Subclass effective visibility 'public' should be the same or less permissive than its superclass effective visibility 'private'
I don't want to use BasicRepositoryImpl
anywhere else, so it's declared private
, and I want to use LocalRepository
and RemoteRepository
in other files like this:
class Presenter(val repo: Repository)
val p = Presenter(LocalRepository())
But that error prevents me to create such a hierarchy. Why? What's wrong with it?
The answer is you can't extend the Parent class if it has a private default constructor. You have to make the constructor available to the subclass. In this case you need to have a default constructor that have a protected or public or default access modifier.
No, we cannot override private or static methods in Java. Private methods in Java are not visible to any other class which limits their scope to the class in which they are declared.
When you have a class with only private constructors, you can also change the class to final because it can't be extended at all.
Private constructors in Java are accessed only from within the class. You cannot access a private constructor from any other class. If the object is yet not initialised, then you can write a public function to call the private instructor.
The class and its ancestors must all be accessible from the using class. Otherwise it would be an violation when loading the ancestor class, not just calling its methods or using its functionality. Kotlin is very clean and clear about this in all cases where accessibility is present.
Opening it up a little would allow things that could cause real JVM access violations later, like an inline
function in the public class, inlined into another class, calling the private non accessible something of the ancestor. There are many holes you aren't considering if you feel it is ok to do a mixed model of accessibility like this. The matrix of considerations is larger than only the desire to hide some classes from instantiation.
With the class being abstract, it cannot be used directly other than as an ancestor, so you have some protection already. If you want to block use as an ancestor outside of your module, make its constructor private
or internal
and that will solve that problem:
abstract class BasicRepositoryImpl private constructor() { ... }
Now you have protected direct instantiation (abstract
) or use as a base class (by using abstract
and private constructors) so the last things to do is give it a good name like AbstractBaseRepository
and people will by convention leave it alone.
If you want to discuss "why" this is the design decision, or technical limitation, or protective rule ... then try the discussion forums, a feature or language change suggestion in YouTrack. But beware things are not as simple as they first appear to be. These rules are there for reasons (even if other languages dangerously allow).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With