Getting T.class despite Java's type-erasure

后端 未结 5 846
小鲜肉
小鲜肉 2020-11-30 11:24

I\'m trying to bind an interface to its implementation as read from a configuration file so that I can feed it to my IoC container. Here\'s roughly what I\'m trying to do:<

相关标签:
5条回答
  • 2020-11-30 11:35

    No it's not possible.

    The only exception to Java's type erasure is that via reflection you can find out the parameterized type via reflection on a class's fields.

    0 讨论(0)
  • 2020-11-30 11:41

    You can get the actual type arguments for a generic superclass of a class. This blog post explores the possibilities presented by this, including a nice little trick using trivial anonymous inner classes. To quote directly:

    It turns out that while the JVM will not track the actual type arguments for instances of a generic class, it does track the actual type arguments for subclasses of generic classes. In other words, while a new ArrayList<String>() is really just a new ArrayList() at runtime, if a class extends ArrayList<String>, then the JVM knows that String is the actual type argument for List's type parameter.

    0 讨论(0)
  • 2020-11-30 11:45

    Contrary to what is widely accepted and rarely known type erasure can be avoided, which means that the callee do have the ability to know which generic parameters were employed during the call.

    Please have a look at: Using TypeTokens to retrieve generic parameters

    The article also talks about the experiences of our users with the technique. In a nutshell, we ended up falling back to the...

    Conventional and widely used technique: "Pass class types in constructors"

    0 讨论(0)
  • 2020-11-30 11:47

    You need to explicitly pass the class into the constructor (and store it yourself).

    private final Class<T> clazz;
    
    PropertyImplementationBinder(Class<T> clazz){
        this.clazz = clazz;
    }
    
    public Class<T> getInterfaceClass() {
        return clazz;
    }
    
    0 讨论(0)
  • 2020-11-30 12:01

    Btw. The example static method getType in article from @Richard Gomes has two errors. it should go like this:

    static public Class<?> getType(final Class<?> klass, final int pos) {
        // obtain anonymous, if any, class for 'this' instance
        final Type superclass = klass.getGenericSuperclass();
    
        // test if an anonymous class was employed during the call
        if ( !(superclass instanceof ParameterizedType) ) {
                throw new RuntimeException("This instance should belong to an anonymous class");
        }
    
        // obtain RTTI of all generic parameters
        final Type[] types = ((ParameterizedType) superclass).getActualTypeArguments();
    
        // test if enough generic parameters were passed
        if ( pos >= types.length ) {
                throw new RuntimeException(String.format("Could not find generic parameter #%d because only %d parameters were passed", pos, types.length));
        }
    
        if (!(types[pos] instanceof Class<?>)) {
                throw new RuntimeException("Generic type is not a class but declaration definition(all you get is \"[T]\") " + types[pos]);
        }
        // return the type descriptor of the requested generic parameter
        return (Class<?>) types[pos];
    }
    

    Unfortunately it's still not the magic bullet because it works if you have in code explicitly

    getType(new SomeObject<String>(){}.class, 0) // you get String.class
    

    but if you call this on something like

    getType(new SomeObject<T>(){}.class, 0) // you get T as TypeVariable<D> and not actuall class of it
    

    Just name T.

    0 讨论(0)
提交回复
热议问题