Почему этот код работает в демонстрации наследования Java?

Я новичок в 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

Спасибо

Может ли кто-нибудь объяснить, почему это происходит? Меня смущают два момента:

  1. Почему super.name работает в этой программе по сравнению с двумя другими утверждениями?
  2. Почему меняется поле name подкласса, а не суперкласса, как должно относиться super?

Вы используете внутренние классы. Пробовали ли вы сделать занятия Person и Worker совершенно отдельными, независимыми классами? Другими словами, создайте файл Person.java для класса Person и отдельный файл Worker.java для класса Worker, а затем посмотрите, получите ли вы такое же поведение.

Abra 11.08.2024 07:31

Спасибо, Абра, когда я разделяю их на два отдельных файла классов, «super.name» больше не компилируется.

Esche 11.08.2024 07:36

@Abra, где в документации указано такое поведение для внутренних классов?

rb612 11.08.2024 07:44

@ rb612 rb612 Я не знаю, где указано такое поведение для внутренних классов, поэтому я опубликовал комментарий, а не ответ, т. е. это было скорее предложение. Может быть, в Спецификациях Java SE?

Abra 11.08.2024 08:08

вызвать getName(), наверное, было бы уместнее...

user85421 11.08.2024 09:38
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
5
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Есть несколько недоразумений.

Частные поля не наследуются, поэтому 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 текущего объекта, но при этом текущий объект рассматривается как экземпляр суперкласса текущего класса.

Спасибо, Подметальщик, ты мне очень помог! 😊

Esche 11.08.2024 08:23

Другие вопросы по теме