#java #oop #polymorphism #object-oriented-analysis
#java #ооп #полиморфизм #объектно-ориентированный анализ
Вопрос:
Я новичок в программировании на Java. Пожалуйста, рассмотрите следующий фрагмент кода.
public class Animal {
public void mate( /*what should I put here?*/ anotherAnimal ) {
}
}
public class Cat extends Animal {
}
public class Dog extends Animal {
}
Я хочу написать метод Animal.mate()
таким образом, чтобы при вызове метода из объекта подкласса аргумент, передаваемый методу, должен быть объектом того же подкласса, в противном случае возникает ошибка компилятора. Например:
Cat cat = new Cat();
Dog dog = new Dog();
Animal randomAnimal = new Animal();
Cat trueLove = new Cat();
cat.mate( dog ); // raises a compiler error
cat.mate( randomAnimal ); //compiler error
cat.mate( trueLove ); //passes compiler check
Возможно ли то, о чем я спрашиваю? У меня есть смутное ощущение, что это можно было бы сделать с помощью дженериков.
Комментарии:
1. Вы могли бы использовать
Animal<A extends Animal>
,Cat extends Animal<Cat>
иmate(A partner)
.2. Как насчет:
Animal a = new Cat(); a.mate(new Animal());
Вы ожидаете, что это сработает или нет?3. @Sweeper Было бы лучше, если бы вы могли дать мне что-то, что заставляет его работать, но я буду достаточно счастлив для чего-то, что только заставляет
Cat cat = new Cat(); cat.mate( new Cat() )
работать4. Так вы думаете,
a.mate(new Animal());
следует скомпилировать? Я так не думаю. Однако во время выполненияa
сохраняетсяCat
объект, аCat
объекты не могут сопрягаться сAnimal
объектами, верно?
Ответ №1:
Нет способа заставить компилятор предотвращать все неудачные вызовы. Даже если вы параметризуете Animal
, все равно было бы возможно выполнить что-то вроде cat.mate(dog)
во время выполнения.
Если этого требует ваша бизнес-логика, то лучше всего выполнить проверку с помощью чего-то подобного:
public class Animal {
public final void mate(Animal anotherAnimal ) {
if(!this.getClass().equals(anotherAnimal.getClass())) {
throw new IllegalArgumentException();
}
}
}
Если вы делаете это главным образом для улучшения проверки типов во время компиляции, то вы можете использовать дженерики, зная ограничения:
class Animal<T extends Animal<T>> {
public final void mate(T anotherAnimal) {
}
}
Это сработает, если пользователи вашего API используют подклассы, а не Animal
тип, и они не используют необработанные типы.
Cat c = new Cat();
c.mate(new Cat());
c.mate(new Dog());//fails
Animal animal = c; //raw type
animal.mate(new Dog()); //only a warning
Ответ №2:
ваша проблема связана с полиморфизмом. используйте суперкласс в качестве типа параметра в методе mate.суперкласс — это Animal. это код:
public class Animal {
public void mate(Animal animal) {
System.out.println("Animals mating");
}
@Override
public String toString() {
return "Animal";
}
public class Dog extends Animal {
@Override
public String toString() {
return "Dog";
}
public class Cat extends Animal {
@Override
public void mate(Animal obj) {
System.out.println("cat mating with " obj );
}
@Override
public String toString() {
return "cat";
}}
и запустите свой код в основном методе. ошибки исчезли, и это ответ:
cat mating with Dog.
cat mating with Animal.
cat mating with cat.
для лучшего ответа вместо того, чтобы говорить cat или dog , вы можете определить поле name в классе Animal.