I try to understand why there is a difference between accessibility of class members when speaking about constructors.
Consider the following example:
class A { static class B { private B(String s) {} private void foo() {} } static class C extends B { public C(String s) { super(s); // call B(String), which is private, and obviously accessible } void bar() { foo(); // compilation error (symbol unknown), as B.foo() is private } } }
Private members of A
, as being private, should not be accessible from B
. For fields and methods, it is the case, but it seems that constructors are not following the same rule.
From the JLS-8 (6.6.1. Determining Accessibility), we can read:
[...]
A member (class, interface, field, or method) of a reference type, or a constructor of a class type, is accessible only if the type is accessible and the member or constructor is declared to permit access:
[...]
Otherwise, the member or constructor is declared
private
, and access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.
Can anyone explain me why the constructor is accessible from C
, even while being declared private
?
A private constructor does not allow a class to be subclassed. A private constructor does not allow to create an object outside the class. If all the constant methods are there in our class we can use a private constructor. If all the methods are static then we can use a private constructor.
Private constructors are used to prevent creating instances of a class when there are no instance fields or methods, such as the Math class, or when a method is called to obtain an instance of a class.
No, Constructors can be public , private , protected or default (no access modifier at all). Making something private doesn't mean nobody can access it. It just means that nobody outside the class can access it.
The default constructor is a public no arguments constructor. To be more specific it has the same access level as the class, so public in a public class, private in a private class, etc. In your second example you are creating a package access level constructor.
The method foo()
is private, so you don't inherit it and can't call it directly from the C
class.
However, you can see private methods and constructor from B
since everything is declared in the same containing class, and access them with super
, which is why super()
works. In the same way, you can access foo
with super.foo()
.
Note that you can redefine a new foo method in C
, but this method will not override B.foo()
.
So the trick here might be the following :
you cannot access foo
because it is declared private so you don't inherit it in C.
However, as was noted in comments you can access super.foo();
because super
refers to a type that is declared in the same top level class (see JLS 6.6.1 for this).
Then the trick is that calling super(s)
can be viewed as calling super.<init>(s)
which ends up being the same case as super.foo()
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