Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Generic method to get an instance from a class parameter

I have a generic class with subclasses:

class Item<T>
{
     //
}

class IntItem extends Item<Integer>
{
    //
}

I need a method to get an instance of Item from its class. I tried methods like:

<T extends Item<T>> T getItem(Class<T> itemClass)
{
  return ...
}


<T> Item<T> getItem(Class<Item<T>> itemClass)
{
    return ...
}

But it does not work:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

// Does not compile: "inference variable T has incompatible equality constraints Integer,IntItem"
IntItem ii = getItem(IntItem.class); 

What is the correct way to do this ?

EDIT

Note that question is only related to the generics/method signatures.

Same question but passing an item as parameter:

IntItem ii = getItem2(anIntItem); 

static <T extends Item<E>,E> T getItem2(T item)
{ 
     // Does not compile: "error: incompatible types: Item cannot be converted to T"
     return getItem(item.getClass();
}

>Solution :

Firstly, your getItem method needs a separate generic parameter to set on your Item parameter (I’m going to use E). Secondly, just use Class#newInstance:

public static <T extends Item<E>, E> T getItem(Class<T> itemType)
        throws InstantiationException, IllegalAccessException {
    return itemType.newInstance();
}

You can also omit the extends Item<?> part entirely. While this will allow the method to instantiate instances of other types, it will still work perfectly for Item types.

If in the future you wanted to add parameters to your item constructors, you could use Class#getConstructor(Class<?>...) or Class#getConstructors() to find the constructor you want to use, then
Constructor#newInstance(Object...) to create your instance. Here are two examples:

// This example does NOT work with null arguments
public static <T> T getItem(Class<T> itemType, Object... arguments)
        throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException,
        IllegalArgumentException, InvocationTargetException {
    Class<?>[] parameterTypes = Arrays.stream(arguments).map(Object::getClass).toArray(Class[]::new);
    return getItem(itemType, parameterTypes, arguments);
}

// This example works with null arguments
public static <T> T getItem(Class<T> itemType, Class<?>[] parameterTypes, Object[] arguments)
        throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException,
        IllegalArgumentException, InvocationTargetException {
    Constructor<T> constructor = itemType.getConstructor(parameterTypes);
    return constructor.newInstance(arguments);
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading