Видимость частных конструкторов Java
Я пытаюсь понять, почему существует разница между доступностью членов класса, когда речь идет о конструкторах.
Рассмотрим следующий пример:
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
}
}
}
Частные члены A
, как частные, не должны быть доступны из B
. Для полей и методов это так, но кажется, что конструкторы не выполняют одно и то же правило.
Из JLS-8 (6.6.1. Определение доступности), мы можем прочитать:
[...]
Элемент (класс, интерфейс, поле или метод) ссылочного типа или конструктор типа класса доступен только в том случае, если тип доступен и член или конструктор объявлен для разрешения доступа:
-
[...]
-
В противном случае член или конструктор объявляется private
, и доступ разрешен тогда и только тогда, когда он встречается внутри тела класса верхнего уровня (§7.6), который включает объявление члена или конструктора.
Может ли кто-нибудь объяснить мне, почему конструктор доступен из C
, даже будучи объявленным private
?
Ответы
Ответ 1
Метод foo()
является закрытым, поэтому вы не наследуете его и не можете вызвать его непосредственно из класса C
.
Однако вы можете видеть частные методы и конструктор из B
, поскольку все объявлено в том же содержащем классе и доступ к ним с помощью super
, поэтому работает super()
.
Таким же образом вы можете получить доступ к foo
с помощью super.foo()
.
Обратите внимание, что вы можете переопределить новый метод foo в C
, но этот метод не будет отменять B.foo()
.
Ответ 2
Таким образом, здесь может быть трюк:
вы не можете получить доступ к foo
, потому что он объявлен приватным, поэтому вы не наследуете его в C.
Однако, как было отмечено в комментариях, вы можете получить доступ к super.foo();
, потому что super
относится к типу, объявленному в том же классе верхнего уровня (см. JLS 6.6.1 для этого).
Тогда фокус в том, что вызов super(s)
можно рассматривать как вызывающий super.<init>(s)
, который заканчивается тем же случаем, что и super.foo()
Ответ 3
Метод Foo() недоступен в классе C, поскольку метод foo() является частным и приватным методом, который не может быть унаследован базовым классом.
Для конструкторов КОНСТРУКТОРЫ НИКОГДА НИКОГДА НЕ БУДУТ ВЕРНУТЬСЯ. Кроме того, я скомпилировал этот код:
class Vehicle{
int speed=50;
private Vehicle()
{
System.out.println("Private Vehicle constructor");
}
}
public class Bike4 extends Vehicle{
int speed=100;
Bike4()
{
super();
System.out.println("Hi I n constructor");
}
void display(){
System.out.println(super.speed);//will print speed of Vehicle now
}
public static void main(String args[]){
Bike4 b=new Bike4();
b.display();
}
}
И получите ошибку времени компиляции: Vehicle() имеет личный доступ к транспортному средству супер(); ^
Что явно указывает, что к закрытому конструктору нельзя получить доступ с помощью супер. Если мы можем инициализировать или получить доступ к частному конструктору, то какой смысл в создании частного конструктора.