Как я могу обратиться к типу текущего класса?

Это трудно объяснить, но я везде искал, и я не нашел хорошего ответа.

Я также видел вопросы о переполнении стека Как я могу обратиться к типу класса, который реализует интерфейс на 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();
    }
}