Стирание типов дженериков в Java

вот код:

public class Main {
    public static void main(String[] args) {
        Gen<Integer> g = new Gen<Integer>(5);

        System.out.println(g.getClass());
        System.out.println(g.ob.getClass());
    }
}

class Gen<T> {
    T ob;

    public Gen(T x) {
        ob = x;
    }
}

и вот результат

class Gen               // This I understand
class java.lang.Integer // But if type erasure is happening, shouldn't this be java.lang.Object?

Я понимаю, что параметр типа T стирается во время выполнения, но тогда почему параметр типа ob выжившие во время выполнения?

5 ответов


Неа!

рассмотрим следующий пример:

Object x = new Integer(1);
System.out.println(x.toString());

вы получаете 1.

но разве я не должен получить объект.toString ()?

нет. В то время как x ссылка типа Object, фактическим референтом является Integer, поэтому во время выполнения,Integer реализация toString называется.

он же getClass.


стирания типа происходит. Generics-это система проверки типа времени компиляции. Во время выполнения вы все еще получаете класс (это информация о типе времени выполнения). Связанная документация по стиранию типа говорит (частично)

дженерики были введены в язык Java, чтобы обеспечить более жесткие проверки типов во время компиляции и обобщенного программирования. Для реализации дженериков компилятор Java применяет тип erasure к:

заменить все параметры типа в универсальных типах с их границами или объектом, если параметры типа неограниченны. Таким образом, созданный байт-код содержит только обычные классы, интерфейсы и методы.

ваш экземпляр имеет тип, это Object. Но Object ссылка может ссылаться на любой подкласс (который является каждым классом) в Java. Вы получаете тип, на который он ссылается.


независимо от типа переменной, возвращаемое значение getClass() зависит от переменной содержание. Итак, поскольку у вас в основном есть переменная Object ob, которая содержит Integer (код int был преобразован в него в то время, когда вы предоставили его в качестве параметра этого конструктора), вывод ob.getClass() is class java.lang.Integer.

кроме того, о вашем вопросе о том, почему getClass() запоминает аргумент типа: это не так. Все, что он делает, это определяет класс контента. Для пример:

class Foo {
    public Foo() {}
}

class Bar extends Foo {
    public Bar() {}
}

class Baz<T> {
    public T object;

    public Baz(T object) { this.object = object; }
}

если теперь запустить следующий фрагмент...

public static void main(String... args) {
    Baz<Foo> obj = new Baz(new Bar());
    System.out.println(obj.object.getClass());
}

Вы заметите, что выход не class Foo, это class Bar.


потому что при компиляции класс Gen имеет объект ob; дженерики исчезают из конечного продукта. Угловые скобки играют роль только во время компиляции, во время статической проверки типа. Это то, что компилятор может сделать для вас, чтобы дать вам более душевное спокойствие, чтобы заверить вас, что вы используете правильно сборов и других видах переутверждаются.

фактический объект, назначенный ob во время выполнения, является экземпляром класса Integer и ob.getClass () служит для того, чтобы узнать фактический класс объекта, на который ссылается указатель -> следовательно, вы увидите на Java.ленг.Напечатанное целое число.

помните, что выходит эффективно класс Gen { Object ob; ... }


поскольку мое первое воздействие дженериков было с C#, потребовалось время, чтобы понять, какой тип стирания находится в java.

но после лучшего понимания Java generics я понял, что в моем вопросе я смешиваю 2 отдельные темы : Generics и Reflection.

главный вопрос был , почему второй вызов здесь

 System.out.println(g.getClass());
 System.out.println(g.ob.getClass());

вернулся java.lang.Integer вместо java.lang.Object.

глядя на документы для getClass(), ответ становится очевидным

возвращает время работы класс этого объекта.

и getClass() не возвращает тип ссылки, но фактический объект, на который ссылается ссылка.

например :

Object o =  "abc";
System.out.println(o.getClass());

вывод не будет типом ссылки java.lang.Object а фактический тип объекта java.lang.String.