Как проверить (универсальный (универсальный аргумент))?

Фон (что мы недействительно надо беспокоиться)

Это вопрос, полученный изПостроить родовое дерево с наследованием , Я открываю этот вопрос как отдельный вопрос, потому что это связано не только с проблемой дерева. Это скорее общая проблема и проблема класса.

Вопрос

Чтобы лучше проиллюстрировать коды, у нас естьTree класс, аSubTree класс иWrongSubTree учебный класс:

class Tree {
}
class SubTree extends Tree {
}
class WrongSubTree extends Tree {
}

При создании объекта мы хотели бы проверить, равен ли универсальный аргумент классу самого объекта:

Tree tree01 = new Tree();                 // equals : OK
Tree tree02 = new Tree();           // (!) not equals
SubTree tree03 = new SubTree();     // equals : OK
WrongSubTree tree04 = new WrongSubTree(); // (!) not equals

(Обратите внимание, что 4 строки выше не имеют ошибок компиляции и исключений времени выполнения).

Мое испытание

Для этого мы пытаемся добавитьClass параметр в конструкторах:

class Tree {
    public Tree(Class clazz) {
        System.out.println(this.getClass());
        System.out.println(clazz);
        System.out.println();
        if (this.getClass() != clazz)
            throw new RuntimeException();
    }
}
class SubTree extends Tree {
    public SubTree(Class clazz) {
        super(clazz);
    }
}
class WrongSubTree extends Tree {
    public WrongSubTree(Class clazz) {
        super(clazz);
    }
}

(Приведенные выше определения классов являются допустимыми кодами Java.)

проблема

Но я нене знаю, как вызвать этот конструктор:

Tree tree01a = new Tree(Tree.class);
// The constructor Tree(Class) is undefined

Tree tree01b = new Tree(Tree.class);
// Syntax error, insert "Dimensions" to complete ArrayType

Обе 2 строки выше вызывают ошибки компиляции.

я думаю, это потому, что конструкторpublic Tree(Class clazz) {} ожидаетClass, но нетClass, Тем не менее, мы не можем сделать.Tree.class

Причина в том, что я пытался изменить класс на:

class Tree {
    public Tree(Class clazz) {            // changed
        System.out.println(this.getClass());
        System.out.println(clazz);
        System.out.println();
        if (this.getClass() != clazz)
            throw new RuntimeException();
    }
}
Tree tree01a = new Tree(Tree.class);

Нет ошибки компиляции.

Однако следующее вызывает ту же ошибку компиляции:

class Tree {
    public Tree(Class clazz) {       // changed
        System.out.println(this.getClass());
        System.out.println(clazz);
        System.out.println();
        if (this.getClass() != clazz)
            throw new RuntimeException();
    }
}
Tree tree01a = new Tree(Tree.class);
// The constructor Tree(Class) is undefined
Редактировать # 1

На основемой комментарий ниже я попробовал это. Надеюсь, это поможет для вдохновения.

static class SimpleClass {
    private SimpleClass(Object dummy) {
        // dummy constructor, avoid recursive call of the default constructor
    }
    SimpleClass() {
        SimpleClass myself = new SimpleClass(new Object()) {};
        System.out.println(((ParameterizedType) myself.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
        // prints "T"

        TypeReference typeRef = new TypeReference() {};
        System.out.println(typeRef.getType());
        // prints "Main.Main$SimpleClass"
    }
    void func() {
        SimpleClass myself = new SimpleClass(new Object()) {};
        System.out.println(((ParameterizedType) myself.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
        // prints "T"

        TypeReference typeRef = new TypeReference() {};
        System.out.println(typeRef.getType());
        // prints "Main.Main$SimpleClass"
    }
}

public static void main(String[] args) {
    SimpleClass simpleObj = new SimpleClass();
    simpleObj.func();

    SimpleClass outsideSimpleClass = new SimpleClass(){};
    System.out.println(((ParameterizedType) outsideSimpleClass.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
    // prints "class java.lang.String"
}

Обратите внимание, мы все ещене могу получить "класс java.lang.String " внутри ,SimpleClass

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

static class AnotherClass {
    private AnotherClass(Object dummy) {}
}
static class SimpleClass {
    SimpleClass() {
        AnotherClass another = new AnotherClass(new Object()) {};
        System.out.println(((ParameterizedType) another.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
        // prints "T"

        TypeReference anotherTypeRef = new TypeReference() {};
        System.out.println(anotherTypeRef.getType());
        // prints "Main.Main$AnotherClass"
    }
    void func() {
        AnotherClass another = new AnotherClass(new Object()) {};
        System.out.println(((ParameterizedType) another.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
        // prints "T"

        TypeReference anotherTypeRef = new TypeReference() {};
        System.out.println(anotherTypeRef.getType());
        // prints "Main.Main$AnotherClass"
    }
}

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

Насколько я понимаю, мы можем использовать только анонимный подкласс getGenericSuperclass() трюк в месте, где он на самом деле уже знает ответ. Такие как вmain()вот место гдеclass java.lang.String действительно определяется как аргумент типа.

(IMO, если способность этого трюка настолько ограничена, это не очень полезно вообще.)

Ответы на вопрос(1)

Ваш ответ на вопрос