Подтвердить что ты не робот

Переопределить атрибуты

Когда вы переопределяете метод, вы должны сохранить подпись метода и не можете уменьшить его видимость. Теперь я пробовал, что происходит, когда я делаю это с помощью атрибутов. Я был удивлен - ЭТО РАБОТАЕТ! Посмотрите сами:

public class A {

    public Integer myAttribute;

}

public class B extends A {

    public String myAttribute;

}

public class Main {

        public static void main(String[] args) {
        B b = new B();
        b.myAttribute = "myString";
        ((A) b).myAttribute = 1337;
        System.out.println(b.myAttribute);
        System.out.println(((A)b).myAttribute);
    }

}

Таким образом, можно написать атрибут в подклассе с тем же именем attibute, что и в суперклассе, но вы можете использовать различную видимость (модификатор) и тип. Поэтому я бы сказал, что атрибуты в суперклассе и подклассе почти полностью независимы друг от друга.

Теперь, если вы действительно используете одно и то же имя атрибута в суперклассе и подклассе, вы фактически скрываете атрибут суперкласса. При доступе к атрибуту с использованием подкласса вы получаете атрибут подкласса. Но атрибут суперкласса тоже есть! Вы должны выполнить бросок, чтобы получить доступ к атрибуту суперкласса снаружи. Изнутри ключевое слово "супер" должно быть полезно.

Вопрос 1: Теперь в основном у вас есть два разных атрибута с тем же именем. Разве это не перерыв LSP?

Почему я пришел к этой детали: Я экспериментирую с собственной письменной основой сохранения. Я хочу прочитать полное внутреннее состояние объекта и сохранить это состояние. Я читал все значения атрибутов через рефлексию, начиная с подтипа и пересекая суперклассы. Теперь, если в суперклассе и подклассе есть два атрибута с тем же именем, я должен помнить класс, который объявляет атрибут, чтобы он мог сопоставлять значения атрибутов с правильными атрибутами и восстанавливать состояние объекта.

Вопрос 2: Любые другие идеи, как справиться с этой деталью? Вопрос 3: Как другие структуры персистентности справляются с этой деталью?

Я никогда не видел эту деталь в использовании. Возможно, написание двух атрибутов с одним и тем же именем является немного уродливым, но это возможно, и с ним может столкнуться любая инфраструктура persistence. Возможно, есть ситуации, когда этот метод может быть полезен.

Заблаговременно.

4b9b3361

Ответ 1

ORM обычно используют стандарт javabeans, который определяет "свойства". Свойства определяются с помощью метода чтения и/или записи, а не поля, которое они читают/записывают. В 99% случаев свойства являются полем + геттер и сеттер, но это не обязательно. ORM считывает эти свойства и обнаруживает только те поля, которые имеют getters & seters. Так как методы переопределены, а не затенены, проблема исчезла.

Это скорее проблема инкапсуляции, чем нарушение LSP. Полиморфизм не влияет на доступ к полю, поэтому, если у вас есть поле Foo foo = new FooSubclas(); foo.field the value of the Foo`, это означает, что поведение не изменится.

Ответ 2

Вопрос 1: он не прерывает LSP, потому что переменные-члены не являются полиморфными.

Ответ 3

Вопрос 1: LSP около behavioral subtyping, и я бы сказал, что наличие двух членов с тем же именем не изменяет самого поведения.

Вопрос 2: Обнаружьте его (вам все равно нужно отсканировать иерархию классов) и не разрешать его.

Ответ 4

Вопрос 2: Сериализовать/десериализовать только через getters/seters.

Вопрос 3: см. ответ 2.

Ответ 5

Вы не можете переопределить атрибут, а только скрыть его. Это буквально называют скрытыми полями в tutorial. Подробнее об этом blog.

Q1: Нет, он не прерывает LSP, любая ссылка на A a = new B(); a.myAttribute будет по-прежнему ссылаться на A.myAttribute, а не на B.myAttribute.

Q2: Я попытался бы избежать этого, но если вам нужно, вы можете получить доступ к A.myAttribute из B с помощью ключевого слова super.myAttribute.

Q3: Я думаю, что С# допускает то же самое, они используют base вместо super, но у меня нет компилятора С# под рукой, а документация на поле, скрывающаяся на С#, разрежена.