简体   繁体   中英

Is it impossible to instantiate a parameterized type through reflection?

Let's suppose you're writing a library, and it is to act upon a client class that is passed to it (ie client code cannot be changed).

class ClientClass {
    public GenericClientClass<AnotherClientClass>  someField;
}

What I'm trying to do is instantiate someField through reflection. Something like:

class LibraryClass{
    public instantiateAllFields(Object obj){
        //iterate through all fields of obj.class, and instantiate them
    }
}

The only requirement of the client's fields is that a constructor without arguments exists. (eg GenericClientClass() {} )

The purpose of this is to create a highly automated testing library, currently for my own purposes.

I've been able to implement the above for almost all cases (arrays, objects, primitives, generic arrays etc.); however, this particular case has stumped me.

field.getType().newInstance() does not work, since the generic type parameters are removed.

field.getGenericType() doesn't work, because it returns a type, not a class.

If It's a known generic class, I can create a special case to deal with it. For example:

            Class<?> genClass = ((Class<?>)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]);
            JArray jArray = new JArray(true,n,genClass);
            field.set(object, jArray);

...I'm guessing I could do this for things like ArrayList, HashMap etc.

However, I would like to cover the general case, and be able to instantiate any generic class (with a single parameter, and a zero-argument constructor) that may be passed into the library.

Any ideas?

Note that the type of the generic parameter is known . I can get at it through field.getGenericType().

There's no such thing as "an instance of a parameterized type"; or, rather, there's no difference between instances of parameterized types with different type parameters. The type parameter is just something the compiler uses to enforce type correctness.

If you're instantiating it at runtime, the compiler is not in the loop. So you just have to create a "raw"/"wildcard"-typed instance, and cast it; and you have to own the problem of ensuring that the cast actually is safe.

Assuming GenericClientClass is not abstract, and has a constructor without parameters:

someField = (GenericClientClass<AnotherClientClass>) GenericClientClass.class.getConstructor().newInstance();

and deal with the resulting unchecked cast warning appropriately.

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