Я новичок в Java и работаю над демонстрацией наследования. Я озадачен, потому что когда я пытаюсь получить доступ к частному полю суперкласса с помощью name или this.name, компилятор правильно сообщает об ошибке, поскольку во многих учебниках говорилось, что подкласс не имеет доступа к частному полю в суперклассе. Однако когда я использую super.name, ошибок нет, и вызов этого метода, похоже, обновляет поле name в объекте подкласса.
Я использую IDEA с jdk 18, и полный код моей демонстрации показан ниже.
public class IV_extend_class_ver2 {
public static class Person {
//field
private String name = "Person";
//default Constructor
//method
public String getName(){ return this.name; }
public void setName(String name){ this.name = name; }
}
//Worker extends from Person
public static class Worker extends Person {
private int salary;
public int getSalary() { return this.salary; }
public void setSalary(int salary) { this.salary = salary; }
//access the private member in superclass
public String hello() {
return "Hello, " + super.name;
// If write name or this.name, an error would get in IDEA
// But if I wirte super.name,it compiles successfully
// and if I call hello() in next part, it works
}
}
public static void main(String[] args) {
Worker man = new Worker();
System.out.println(man.hello());
man.setName("Bob");
System.out.println(man.hello());
}
}
и результаты будут
Hello, Person
Hello, Bob
Спасибо
Может ли кто-нибудь объяснить, почему это происходит? Меня смущают два момента:
super.name работает в этой программе по сравнению с двумя другими утверждениями?name подкласса, а не суперкласса, как должно относиться super?Спасибо, Абра, когда я разделяю их на два отдельных файла классов, «super.name» больше не компилируется.
@Abra, где в документации указано такое поведение для внутренних классов?
@ rb612 rb612 Я не знаю, где указано такое поведение для внутренних классов, поэтому я опубликовал комментарий, а не ответ, т. е. это было скорее предложение. Может быть, в Спецификациях Java SE?
вызвать getName(), наверное, было бы уместнее...




Есть несколько недоразумений.
Частные поля не наследуются, поэтому Worker не имеет name в качестве одного из своих членов.
Члены класса, объявленные частными, не наследуются подклассами этого класса.
Тем не менее, значение name все еще существует в экземпляре Worker. В конце концов, для работы других методов, таких как getName и setName, это необходимо. См. также: Наследуют ли подклассы частные поля? Это должно ответить на ваш второй вопрос - не существует «поля подкласса» и «поля суперкласса». В этом коде всегда есть только одно поле с именем name.
name доступен в Worker. privateзапрещает доступ за пределами класса верхнего уровня. Класс верхнего уровня в данном случае — IV_extend_class_ver2.
В противном случае объявляется член или конструктор
private. Доступ разрешен только в том случае, если выполняется одно из следующих условий:
- Доступ осуществляется из тела класса или интерфейса верхнего уровня, который включает объявление члена или конструктора.
- [...]
См. также: Почему внутренние классы делают доступными частные методы?
Несмотря на то, что name доступен в Worker, не каждая форма доступа действительна.
Вы не можете написать this.name, потому что this имеет тип Worker и, как упоминалось ранее, Worker не имеет поля с именем name, поэтому выражение недопустимо.
(в данном случае Primary относится к выражению this)
Тип
Primaryдолжен быть ссылочным типомT, иначе произойдет ошибка времени компиляции.Смысл выражения доступа к полю определяется следующим образом:
[...]
Если идентификатор не называет доступное поле-член типа
T, то доступ к полю не определен и возникает ошибка времени компиляции.
Также недопустимо использовать простое имя (т. е. просто писать name), поскольку область (не то же самое, что доступность!) name — это тело класса Person.
Областью объявления члена
m, объявленного или унаследованного классом или интерфейсомC, является все телоC, включая любые вложенные объявления классов или интерфейсов.
Если имя выражения состоит из одного идентификатора, то:
- [...]
- если существует ровно одно объявление, обозначающее локальную переменную, формальный параметр, параметр исключения или поле в области видимости в точке, в которой встречается идентификатор, то имя выражения относится к переменной в области видимости.
- В противном случае возникает ошибка времени компиляции.
super.name допустимо, потому что эта форма ищет поля в суперклассе. Вы можете думать об этом как ((Person)this).name.
Форма
super.Identifierотносится к полю с именемIdentifierтекущего объекта, но при этом текущий объект рассматривается как экземпляр суперкласса текущего класса.
Спасибо, Подметальщик, ты мне очень помог! 😊
Вы используете внутренние классы. Пробовали ли вы сделать занятия
PersonиWorkerсовершенно отдельными, независимыми классами? Другими словами, создайте файлPerson.javaдля классаPersonи отдельный файлWorker.javaдля классаWorker, а затем посмотрите, получите ли вы такое же поведение.