简体   繁体   中英

Usage of Java generics when the type is known only at runtime

Consider the following code:

public class Generics {
    C c; // initialized at runtime

    public void testGenericsCall(Object o) {
        c.myMethod(o);
    }
}

class C<E> {
    public void myMethod(E input) {
    }
}

This is working, but I get warnings because the parametrized class C is used with a raw type. I cannot use a declaration like

C<String> c;

because the type of C is known only at runtime. I also cannot add a type parameter to the class Generics because I need to create objects of this class before knowing the type of C. The declaration

C<?> c;

or

C<? extends Object> c;

would be OK for the compiler, but then the method testGenericsCall does not compile ( "actual argument java.lang.Object cannot be converted to capture#1 of ? by method invocation conversion" )

What is the best way to deal with a situation like this?

EDIT : Note that when I actually (at runtime) create an instance of C, I know its type parameter, this part of the code is type-safe and working well. In the real code, I don't have a single "C" class, but a series of interrelated classes, and there the generics are definitely useful (even if in this simplified example this is not obvious - so please don't just tell me not to use generics :). I already have the compile-time type-safety, but not here, but between C and other classes (not shown here).

I see how in this case I cannot check the type parameter at compile time, that's why I tried to declare it C<?> c . Here I am just looking for the best way to bridge the generic and not-generic code without compiler warnings.

Because of type erasure , there's no way to use generics at runtime. You'll have to deal with your data type programmatically, by checking type or anything (reflection maybe).

You can do it. But through dirty tricks and reflection. Look at below code for example. Courtesy here :

class ParameterizedTest<T> {

/**
 * @return the type parameter to our generic base class
 */
@SuppressWarnings("unchecked")
protected final Class<T> determineTypeParameter() {
    Class<?> specificClass = this.getClass();
    Type genericSuperclass = specificClass.getGenericSuperclass();
    while (!(genericSuperclass instanceof ParameterizedType) && specificClass != ParameterizedTest.class) {
        specificClass = specificClass.getSuperclass();
        genericSuperclass = specificClass.getGenericSuperclass();
    }
    final ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;

    final Type firstTypeParameter = parameterizedType.getActualTypeArguments()[0];
    return (Class<T>) firstTypeParameter;
}



}

//change the type of PrameterizedTest<Integer> to Parameterized<String> or something to    display different output
public class Test extends ParameterizedTest<Integer>{
 public static void main(String... args){
    Test test = new Test();
    System.out.println(test.determineTypeParameter());
}

}

Here on the runtime, you get the Type Parameter. So instead in your class, you will have to define a Class object which gets the class as explained above. Then using Class.newInstance you get a new Object. But you will have to manually handle type cast and so on.

The question is: Is all this worth it??

No according to me as most of it can be avoided by using bounds in generic types and interfacing to the bound type

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM