Java Generics: Accessing Generic Type at runtime

﹥>﹥吖頭↗ 提交于 2019-11-28 06:59:39
haylem

It is true that generics aren't generally known at runtime in Java, because they are implemented with Type Erasure.

Reflecting Generics?

However, you can stil extract some valuable information about the declared types (NOT the runtime objects' types), as presented in Ian Roberston's article Reflecting Generics and Prenkov's article Java Reflection: Generics.

Background on Generics and Type Erasure

Generics where introduced while conserving backwards compatibility at the source qnd binary level, hence some of their limitation, like:

  • the impossibility to have a short-hand form without at least some indicator for generics support (here, the so-called diamond operator <>),
  • the impossibility to inspect generic-types at runtime, because they had to be implemented with Type Erasure.

Further Reading

Anony-Mousse

Well, why don't you look at what guice does? The source is publicly available.

Guice does these things at multiple levels. One that particular sticks out are type literals.

The key point here is that while types are compiled using type erasure (so there is only one class for each type), there still exist multiple Type objects, that do know the generics used. However, the code is optimized independently of that (as it was compiled per class, and not per type).

Have a look at the Java API of ParameterizedType.

So while it is correct that Java Generics are implemented by "type erasure" on a class level, this doesn't completely hold on a Type level. Unfortunately, handling Types is much more tricky than classes. Plus, this also implies that Java cannot optimize generics in the same way that C++ does, in particular for primitive types. An ArrayList<Integer> will by design be an ArrayList<?> containing objects, and not backed by a native int[] array when possible.

Note that this is, however, rather close to keeping track of these things yourself. Say, very naively (it will not work with nested generics), you could just extend ArrayList<T> with a class, that has a field Class<T> contentClass, then you will be able to find out this information at runtime. (A TypeLiteral may be the better choice instead of a Class here, though!) Plus, the JRE will actually not ensure that the list remains consistent. Just like you could cast a ArrayList<Integer> into an untyped ArrayList and add a String object.

I've used this a year or so ago. It could help you out

Type typeOfSrc = type(YourClass.class, clazz);

// type(C, A1,...,An) => C<A1,...,An>
static ParameterizedType type(final Class raw, final Type... args)
{
    return new ParameterizedType()
    {
        public Type getRawType(){ return raw; }

        public Type[] getActualTypeArguments(){ return args; }

        public Type getOwnerType(){ return null; }
    };
}

This allows you to access the Generic type at run time. Basically what you're doing here is storing the Generic information in another class, and using that class for retrieving that information at run time.

vladimir e.

I believe guice uses TypeLiteral to encapsulate generic information in a separate object.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!