Страницы

Поиск по вопросам

суббота, 14 декабря 2019 г.

Java: объясните поведение компилятора

#ооп #компилятор #java #компиляция


Здравствуйте! Столкнулся со странным поведением компилятора, объясните пожалуйста,
почему происходит вывод разных строк.
class EntityModel{
    public String name;
    public EntityModel(){
        this.name = "EntityModel";
    }
    public String getName(){
        return this.name;
    }
}
class Model1 extends EntityModel{
    public String name;
    public Model1(){
        this.name = "Model1";
    }

    @Override
    public String getName(){
        return this.name;
    }
}

Вызов:
EntityModel m = (EntityModel)new Model1();  
System.out.println(m.name);
System.out.println(m.getName());

Вывод: 
EntityModel
Model1

Код на ideone.com
Почему обращение к полю на прямую и через геттер дают разные результаты?    


Ответы

Ответ 1



Хе :) Если коротко, то в Java методы виртуальные, а поля — нет. То есть, привязка метода к имени метода производится на этапе выполнения в соответствии с настоящим, динамическим типом объекта, а вот привязка поля — статическая, производится на этапе компиляции. Так сделано потому, что выставлять наружу открытое поле всё равно очень плохая практика, поэтому доступ к полям можно ускорить за счёт точного определения поля во время компиляции. А вот вызывая публичный метод, программист не ожидает вызова не самого «свежего» метода, так что здесь логичнее виртуальный вызов. (Впрочем, архитекторы C# считают не так, но это уже вопрос дизайна языков.) Это всё ещё один аргумент к тому, чтобы делать все поля private, и получать доступ к ним лишь через getter.

Ответ 2



Потому что в первом случае считывается поле EntityModel.name, а во втором случае обращение к методу EntityModel.getName() приводит к вызову Model1.getName(), поскольку второй метод переопределяет первый. Так работает обращение к полям и методам, и об этом написано в любом учебнике.

Комментариев нет:

Отправить комментарий