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

Что не так с этим примером наследования свойств Java?

Inheritance.java

public class InheritanceExample {
  static public void main(String[] args){
    Cat c = new Cat();
    System.out.println(c.speak());

    Dog d = new Dog();
    System.out.println(d.speak());
  }
}

Animal.java

public class Animal {
  protected String sound;
  public String speak(){
    return sound;
  }
}

Cat.java

public class Cat extends Animal {
  protected String sound = "meow";
}

Dog.java

public class Dog extends Animal {
  protected String sound = "woof";
}

Вывод:

null
null

Мои животные не могут говорить. Так грустно.

4b9b3361

Ответ 1

Поля не являются полиморфными. Вы объявили три совершенно разных поля... те, что были в тэгах Cat и Dog, или спрятали в Animal.

Самый простой (но не обязательно лучший) способ получить ваш текущий код - удалить sound из Cat и Dog и установить значение унаследованного поля sound в конструкторе для Cat и Dog.

Лучшим подходом было бы сделать абстракцию Animal и дать ему защищенный конструктор, который принимает звук... конструкторы Cat и Dog затем вызывают super("meow") и super("woof") соответственно:

public abstract class Animal {
    private final String sound;

    protected Animal(String sound) {
        this.sound = sound;
    }

    public String speak(){
        return sound;
    }
}

public class Cat extends Animal {
    public Cat() {
        super("meow");
    }
}

public class Dog extends Animal {
    public Dog() {
        super("woof");
    }
}

Ответ 2

Вы не можете переопределять поля классов, а только методы. Поле sound в классах Dog и Cat фактически скрывает поле sound в суперклассе Animal.

Однако вы можете получить доступ к полям суперкласса из подклассов, чтобы вы могли сделать что-то вроде этого:

public class Dog extends Animal {
  public Dog() {
    sound = "woof";
  }
}

public class Cat extends Animal {
  public Cat() {
    sound = "meow";
  }
}

Или вы можете создать абстрактный тег Animal и объявить также тег метода speak, а затем определить его в подклассах:

public abstract class Animal {
  public abstract String speak();
}

public class Dog extends Animal {
  public String speak {
    return "woof";
  }
}

public class Cat extends Animal {
  public String speak {
    return "meow";
  }
}

Ответ 3

Вы скрываете поля. sound в Animal не совпадает с String как sound в Cat.

Одно из возможных решений - создать конструктор и просто сказать

super.sound = "meow";

а не в классе класса, говорящем

protected String sound = "meow";

чтобы установить поле.

Ответ 4

Метод будет искать в пространстве имен своего собственного класса для разрешения полей. Хотя методы, определенные в подклассах, могут искать иерархию для разрешения полей, то же самое не верно для классов, определенных выше в иерархии, т.е. Суперклассы не будут смотреть вниз по иерархии для разрешения полей [и их значений]

Ответ 5

Вы shadowing поле, унаследованное от Animal. У вас есть несколько вариантов, но самый красивый способ сделать это - передать звук в конструкторе:

public class Animal {
  private final String sound;
  protected Animal(String sound){
    if (sound == null)
      throw new NullPointerException("sound");
    this.sound = sound;
  }
  public String speak(){
    return sound;
  }
}

public class Cat extends Animal {
  public Cat(){ super("meow"); }
}

public class Dog extends Animal {
  public Dog(){ super("woof"); }
}

Таким образом, вы можете убедиться, что Animal всегда имеет правильный звук, прямо из конструкции.

Ответ 6

Способ Java (TM) - объявить защищенную строку getSound() в Animal.java и реализовать ее в подклассах.

Ответ 7

Ты не позволил своим животным говорить! вы должны сделать следующее:

Cat.java:

public class Cat extends Animal {
//  protected String sound = "meow";

    public Cat(){
        this.sound = "cat";
    }

}

Dog.java:

public class Dog extends Animal {
// protected String sound = "woof";

    public Dog(){
        this.sound = "dog";
    }
}

только потому, что в Cat или Dog есть два члена "звук", а тот, унаследованный от Animal скрывается без значения (поэтому он печатает нуль), другой - для Cat или Dog, которому присваивается значение. Поэтому вы должны использовать указатель 'this', чтобы процитировать исходный "звук" участника.