Как я могу обратиться к типу текущего класса?
Это трудно объяснить, но я везде искал, и я не нашел хорошего ответа.
Я также видел вопросы о переполнении стека Как я могу обратиться к типу класса, который реализует интерфейс на Java? и Как вернуть экземпляр объекта того же типа, что и класс, переданный с использованием Java 6?, но они не могли ответить на мой вопрос. Существует исключение, когда я применяю наследование.
Есть пример, чтобы было легче понять:
Скажем, у меня есть интерфейс под названием SelfMaker:
public interface SelfMaker <SELF>{
public SELF getSelf();
}
И у А есть Собака, которая может размножаться с другими собаками. Итак, собака является "SelfMaker", например:
public class Dog implements SelfMaker<Dog> {
String color;
public String toString() {
return "some " + color + " dog";
}
public Dog procreate(Dog anotherDog) {
Dog son = getSelf();
son.color = color;
return son;
}
@Override
public Dog getSelf() {
return new Dog();
}
}
Но тогда у меня есть DomesticDog, который является Собакой, но у него есть прекрасная семья, которая назвала его. Вот так:
public class DomesticDog extends Dog {
private String name;
public String toString() {
return super.toString() + " named " + name;
}
}
Теперь у меня есть класс, который обрабатывает пары вещей, которые являются "SelfMaker", и позвольте этому классу "Пара". Вот так:
public class Couple<T extends SelfMaker<T>> {
private T first;
private T second;
public String toString() {
return first.toString() + " and " + second.toString();
}
}
ИСКЛЮЧЕНИЕ:
Исключение возникает, когда я хочу создать пару DomesticDog
s. Вот так:
public class CoupleOfDomesticDogs extends Couple<DomesticDog>{
public DomesticDog procreate(){
DomesticDog son = first.procreate(second);
return son;
}
}
Это вызовет исключение из <DomesticDog>
, жалующегося: Bound mismatch: The type DomesticDog is not a valid substitute for the bounded parameter <T extends SelfMaker<T>> of the type Couple<T>
Я уже пытался изменить обобщенную переменную из класса Пара на это: Couple<T extends SelfMaker<?>>
, но "сын" не будет DomesticDog (и я хочу, чтобы "сын" был DomesticDog). Если я добавлю несколько актеров, то он будет компилироваться, но будет менее разборчивым.
Итак... вот вопрос: есть ли способ достичь этого без кастингов и обобщений?
Ответы
Ответ 1
Я не могу думать об этом без кастинга. Ваша проблема будет решена, если вы переопределите методы procreate и getSelf DomesticDog и измените объявление класса Пара как таковая:
public class DomesticDog extends Dog {
private String name;
public DomesticDog procreate(Dog anotherDog) {
return (DomesticDog)super.procreate(anotherDog);
}
public Dog getSelf() {
return new DomesticDog();
}
public String toString() {
return super.toString() + " named " + name;
}
}
public class Couple<T extends SelfMaker<? super T>> {
protected T first;
protected T second;
public String toString() {
return first.toString() + " and " + second.toString();
}
}
Если вы не хотите переопределять getSelf() в каждом подклассе Dog, вы можете внести следующие изменения в класс Dog:
public Dog getSelf() {
Class<? extends Dog> thisClass = this.getClass();
try {
return thisClass.newInstance();
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
}
throw new UnsupportedOperationException(thisClass
+ " does not supply a public no-arg constructor");
}
Это гарантирует, что каждое значение, возвращаемое getSelf(), является экземпляром this.getClass()
. Но вам все равно придется указывать возвращаемое значение procreate() для подклассов. Невозможно явно указать возвращаемый тип как this.getClass()
.
Ответ 2
Вам нужно будет сделать Dog
общий и абстрактный, с параметром типа, который указывает результат getSelf()
. Каждый тип Dog
затем должен реализовать это с собой как параметр:
public abstract class Dog<T> implements SelfMaker<T> {
String color;
public String toString() {
return "some " + color + " dog";
}
public T procreate(T anotherDog) {
T son = getSelf();
son.color = color;
return son;
}
}
public class DomesticDog extends Dog<DomesticDog> {
private String name;
public String toString() {
return super.toString() + " named " + name;
}
@Override
public DomesticDog getSelf() {
return new DomesticDog();
}
}