Переопределить тип параметра класса в Java - PullRequest
0 голосов
/ 27 марта 2019

Возможно ли переопределить параметр класса в Java? Я почти уверен, что это невозможно, но ...

public class Dad {
  protected Building home;

  public Dad() {
  }

  public Building getHome(){
     return this.home;
  }
}

public class Son extends Dad {
  protected Shack home;

  public Son () {
    super();
    this.home = new Shack();
  }
}

public Shack extends Building{
 (...)
}

По-видимому, нет проблем с добавлением двух параметров с одинаковым именем, но я не уверен, что эти два параметра "связаны" вместе.

Когда я вызываю функцию getHome() из объекта Son, он возвращает нулевой объект. Это имеет смысл, потому что объект Dad не имеет инициализированного объекта Building. Даже если Son имеет инициализированный Shack объект, который расширяет класс Building. (Я не знаю, достаточно ли я ясен ...)

Простым решением было бы просто инициализировать home объектом Shack и приводить home в Shack всякий раз, когда это необходимо. Но я хотел бы знать, есть ли другой способ сделать это.

Ответы [ 3 ]

1 голос
/ 27 марта 2019

Вы не должны повторно объявлять поля с одинаковыми именами в подклассах. Это потому, что поля скрыты, а не переопределены.

Компилятор не будет жаловаться на это, но в этом случае есть две переменные. Dad.home не присваивается конструктором в Son. Так что new Son().getHome() вернет null в этом примере, и это потому, что getHome() знает только о Dad.home.

Оттуда, где вы находитесь, лучше всего просто удалить свойство home из Son, а еще лучше сделать его private в Dad и передать его значение из подкласса с помощью параметров конструктора.

1 голос
/ 27 марта 2019

Может быть, вам следует реорганизовать эти два класса с помощью обобщений:

Абстрактный суперкласс:

public abstract class Person<T extends Building> {
    protected T home;

    public T getHome(){
        return this.home;
    }
}

Класс папы:

public class Dad extends Person<Building> {

    public Dad() {
        home = new Building();
    }

}

Класс сына:

public class Son extends Person<Shack> {

    public Son () {
        home = new Shack();
    }

}

Вы можете проверить, имеет ли поле home правильный тип (и также не ноль), с помощью простого теста:

public class SonAndDadTest {

    @Test
    public void sonTest(){
        Son son = new Son();
        Assert.assertNotNull(son.getHome());
        Assert.assertEquals(son.getHome().getClass(), Shack.class);
    }

    @Test
    public void dadTest(){
        Dad dad = new Dad();
        Assert.assertNotNull(dad.getHome());
        Assert.assertEquals(dad.getHome().getClass(), Building.class);
    }

}
1 голос
/ 27 марта 2019

Поля не могут быть переопределены. В вашем случае поле от сына просто скрывает поле от папы:

Внутри класса поле с тем же именем, что и поле в суперкласс скрывает поле суперкласса, даже если их типы разные. Внутри подкласса поле в суперклассе не может быть ссылается на его простое имя. [...] В общем-то говоря, мы не рекомендуем скрывать поля, так как это затрудняет код читать.

Функция GetHome объявлена ​​в классе Dad, поэтому она может видеть только home форму экземпляра Dad, которая является нулевой. Вы можете получить доступ к папе home как super.home из экземпляра сына.

Вы можете извлечь суперкласс или интерфейс.

interface HasHome {
    Building getHome();
}

class Dad implements HasHome {
    protected Building home;

    public Dad() {
        this.home = new Building();
    }

    @Override
    public Building getHome(){
        return this.home;
    }
}

class Son implements HasHome { // Or extends Dad
    protected Shack home;

    public Son () {
        super();
        this.home = new Shack();
    }

    @Override
    public Shack getHome() {
        return home;
    }
}

Существует другой вопрос , какой путь выбрать. Более того, супертип может быть общим, как показывает @Lorelorelore.

...