Как общее стирание Java влияет на использование newInstance()?

Основываясь на документации Java:

Во время процесса стирания типа компилятор Java стирает все параметры типа и заменяет каждый его первой границей, если параметр типа ограничен, или Object, если параметр типа не ограничен.

Дело в том, что с таким классом:

public class MyCreator<T> { 
    Class<T> kind; 

    MyCreator(Class<T> kind) {
        this.kind = kind; 
    }

    void printInstanceClass() throws Exception{ 
        System.out.println(kind.newInstance().getClass());
    }

    public static void main(String[] args) throws Exception{ 
        MyCreator<String> myCreator = new MyCreator<String>(String.class);

        myCreator.printInstanceClass();
    } 
}

printInstanceClass() Метод печатает на самом деле "класс java.lang.String".

Если компилятор заменяет T внутри класса на Object, я думаю, что информация о Class также связана с kind удаляется и заменяется классом. Итак, как можно newInstance() метод возвращает экземпляр String вместо объекта Object?

3 ответа

Решение

Хитрая часть является String.class параметр. Это не параметр типа, а обычный старый параметр, как String[] args, Итак Class<T> kind будет String.class Таким образом printInstanceClass() может получить к нему доступ во время выполнения.

Это обычная практика, предложенная и в Effective Java.

Таким образом, после стирания типа этот код логически эквивалентен следующему:

public class MyCreator { 
    Class kind; // this will be String.class at runtime

    MyCreator(Class kind) {
        this.kind = kind; 
    }

    void printInstanceClass() throws Exception{ 
        System.out.println(kind.newInstance().getClass());
    }

    public static void main(String[] args) throws Exception{ 
        MyCreator myCreator = new MyCreator(String.class);

        myCreator.printInstanceClass();
    } 
}

Вы передаете String.class (который НЕ стирается, но конкретный класс сохраняется во время выполнения), а затем вызываете newInstance для этого класса, который возвращает String.

Вывод проверяет конкретный объект (String) и отображает его класс.

Информация о классе (типе), который вы передали в качестве общего аргумента вашего myCreator объект удален, но не информация, хранящаяся внутри kind объект.

С помощью Class<?> Методы объекта в порядке, но если вы пытались получить информацию о классе из универсального T введите, что вы встретите ошибку компиляции, например:

void printInstanceClass() throws Exception{ 
    System.out.println(T.class.newInstance().getClass()); // error!
}

Хотя это нелегко, обходные пути для выполнения вышесказанного тоже существуют.

Другие вопросы по тегам