Как я могу исправить этот код, чтобы он работал правильно?
Он должен напечатать bau bau
и miao
.
Код:
class Animal {
// Nothing to define, this is only an example
}
class Dog extends Animal {
void say() {
print("bau bau");
}
}
class Cat extends Animal {
void say() {
print("miao");
}
}
void setup() {
Dog dog = new Dog();
Cat cat = new Cat();
ArrayList<Animal> list = new ArrayList<Animal>();
list.add(dog);
list.add(cat);
for (Animal obj:list) {
if (obj.say != null) obj.say(); //error here: say() is undefined
}
}
Исключение:
say cannot be resolved or is not a field
Спасибо вам за помощь
Поскольку the say() method should be optional
(см. Комментарии к вопросу OP), кажется, что вам нужен дополнительный интерфейс, например:
interface Sayable {
void say();
}
Затем:
class Dog extends Animal implements Sayable {
@Override
public void say() {
System.out.println("bau bau");
}
}
class Cat extends Animal implements Sayable {
@Override
public void say() {
System.out.println("miao");
}
}
class Rabbit extends Animal {
// a rabbit unfortunately does not speak,
// so don't make it implement Sayable
}
А также:
Dog dog = new Dog();
Cat cat = new Cat();
Rabbit rabbit = new Rabbit();
ArrayList<Animal> list = new ArrayList<Animal>();
list.add(dog);
list.add(cat);
list.add(rabbit);
for (Animal obj : list) {
if (obj instanceof Sayable) {
Sayable sayable = (Sayable) obj;
sayable.say();
}
}
Печать:
bau bau
miao
Для хорошего порядка всегда используйте @Override
. Это улавливает опечатки в имени метода или типах параметров.
class Animal {
//nothing to defines, this is only an example
void say() {
}
}
class Dog extends Animal {
@Override
void say() {
print("bau bau");
}
}
class Cat extends Animal {
@Override
void say() {
print("miao");
}
}
Теперь say()
можно называть любым Animal
, фактически ничего не делая (ваше упоминание о том, say
оно необязательно, - Черепаха ничего не говорит и, следовательно, не имеет собственного чрезмерного say
).
Тип вашего ArrayList
- это животное, поэтому нет гарантии, что метод say()
существует в любом подклассе животного.
Вы можете добавить эту гарантию, создав абстрактный метод:
abstract class Animal {
abstract void say();
}
Это гарантирует, что все подклассы Animal
будут иметь метод say()
(если они этого не делают, они не будут компилироваться.) Обратите внимание: теперь Animal является абстрактным, что делает его необратимым напрямую (поскольку любой класс с абстрактными методами также имеет быть абстрактным.)
Если это не то, что вы хотите, альтернативой может быть предоставление поведения по умолчанию в методе say у животных:
class Animal {
@Override
void say() {
System.out.println("A bit confused");
}
}
При таком поведении подклассы не вынуждены внедрять такой метод - если они этого не делают, тогда они получают поведение по умолчанию (как указано выше), если они это делают, то они переопределяют поведение по умолчанию с их реализацией и используют вместо этого. При желании (но я рекомендую это сделать), вы можете использовать аннотацию @Override
чтобы указать, что вы должны переопределить метод, как указано выше. Таким образом, если вы по какой-то причине не превзошли его, он не будет компилироваться, что позволит вам обнаружить ошибку раньше.
Тип Animal
не имеет открытого (или любого другого доступного доступа) поля, называемого say
obj.say
Animal
не определяет, say
поэтому, когда вы пытаетесь сослаться на объект Animal
(который может быть Dog
), он не знает, say
существует.
Чтобы он не был опциональным:
package com.rei.online;
import java.util.ArrayList;
class Animal {
}
interface Talking {
void say();
}
class Dog extends Animal implements Talking {
@Override
public void say() {
System.out.println("bau bau");
}
}
class Cat extends Animal implements Talking {
@Override
public void say() {
System.out.println("miao");
}
}
class Whatever {
public static void main(String... args) {
Dog dog = new Dog();
Cat cat = new Cat();
ArrayList<Animal> list = new ArrayList<Animal>();
list.add(dog);
list.add(cat);
for (Animal obj:list) {
if (obj instanceof Talking) {
Talking talker = (Talking) obj;
talker.say();
}
}
}
}