74

I would like to create an object of Generics Type in java. Please suggest how can I achieve the same.

Note: This may seem a trivial Generics Problem. But I bet.. it isn't. :)

suppose I have the class declaration as:

public class Abc<T> {
    public T getInstanceOfT() {
       // I want to create an instance of T and return the same.
    }
}
Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
Mohd Farid
  • 2,010
  • 1
  • 17
  • 23
  • How do you come about knowing what "T" is? Which part of the program "tells" you which T to use? – seh Mar 12 '10 at 16:26
  • 1
    I'd also suggest the Generics FAQ: http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html – Hosam Aly Mar 12 '10 at 16:45

12 Answers12

80
public class Abc<T> {
    public T getInstanceOfT(Class<T> aClass) {
       return aClass.newInstance();
    }
}

You'll have to add exception handling.

You have to pass the actual type at runtime, since it is not part of the byte code after compilation, so there is no way to know it without explicitly providing it.

buræquete
  • 14,226
  • 4
  • 44
  • 89
Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
28

In the code you posted, it's impossible to create an instance of T since you don't know what type that is:

public class Abc<T>
{
       public T getInstanceOfT()
       {
           // There is no way to create an instance of T here
           // since we don't know its type
       }
} 

Of course it is possible if you have a reference to Class<T> and T has a default constructor, just call newInstance() on the Class object.

If you subclass Abc<T> you can even work around the type erasure problem and won't have to pass any Class<T> references around:

import java.lang.reflect.ParameterizedType;

public class Abc<T>
{
    T getInstanceOfT()
    {
        ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass();
        Class<T> type = (Class<T>) superClass.getActualTypeArguments()[0];
        try
        {
            return type.newInstance();
        }
        catch (Exception e)
        {
            // Oops, no default constructor
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args)
    {
        String instance = new SubClass().getInstanceOfT();
        System.out.println(instance.getClass());
    }
}

class SubClass
    extends Abc<String>
{
}
Martin
  • 37,119
  • 15
  • 73
  • 82
  • Your reason is wrong since the same could be said of `Class` yet here we *can* create an instance. – Konrad Rudolph Mar 12 '10 at 16:43
  • Don't agree with you. I have been able to achieve the same .. check my answer. – Mohd Farid Mar 12 '10 at 16:59
  • well, of course it's possible to instantiate `T` **if** you know its type (through `Class`) **and** that type has a default constructor. This was however not the case in the originally posted code. – Martin Mar 12 '10 at 18:18
  • 1
    Excellent.... One of the best solution to get generic type instance without new keyword...Most of the answers posted here will throw null pointer exception else it requires to pass .class and use new keyword .........Yours is rocking man....thanks...... – TechDog Dec 29 '16 at 14:07
  • 1
    [`clazz.newInstance()` is deprecated as of Java 9](https://docs.oracle.com/javase/9/docs/api/java/lang/Class.html#newInstance--): _can be replaced by `clazz.getDeclaredConstructor().newInstance()`_. – Gerold Broser Jun 11 '20 at 12:54
15

What you wrote doesn't make any sense, generics in Java are meant to add the functionality of parametric polymorphism to objects.

What does it mean? It means that you want to keep some type variables of your classes undecided, to be able to use your classes with many different types.

But your type variable T is an attribute that is resolved at run-time, the Java compiler will compile your class proving type safety without trying to know what kind of object is T so it's impossible for it to let your use a type variable in a static method. The type is associated to a run-time instance of the object while public void static main(..) is associated to the class definition and at that scope T doesn't mean anything.

If you want to use a type variable inside a static method you have to declare the method as generic (this because, as explained type variables of a template class are related to its run-time instance), not the class:

class SandBox
{
  public static <T> void myMethod()
  {
     T foobar;
  }
}

this works, but of course not with main method since there's no way to call it in a generic way.

EDIT: The problem is that because of type erasure just one generic class is compiled and passed to JVM. Type checker just checks if code is safe, then since it proved it every kind of generic information is discarded.

To instantiate T you need to know the type of T, but it can be many types at the same time, so one solution with requires just the minimum amount of reflection is to use Class<T> to instantiate new objects:

public class SandBox<T>
{
    Class<T> reference;

    SandBox(Class<T> classRef)
    {
        reference = classRef;
    }

    public T getNewInstance()
    {
        try
        {
            return reference.newInstance();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

    public static void main(String[] args)
    {
        SandBox<String> t = new SandBox<String>(String.class);

        System.out.println(t.getNewInstance().getClass().getName());
    }
}

Of course this implies that the type you want to instantiate:

  • is not a primitive type
  • it has a default constructor

To operate with different kind of constructors you have to dig deeper into reflection.

Jack
  • 131,802
  • 30
  • 241
  • 343
  • 3
    Well, it makes perfect sense in .NET, where generics are conceptually quite similar to Java’s. The only real difference is that .NET doesn’t have the type erasure and that is the *technical* difference that makes such a code work in .NET and not in Java. – Konrad Rudolph Mar 12 '10 at 16:41
  • Please ignore it being called from a main method. I have updated the code. Now, we have a getInstanceOfT method. – Mohd Farid Mar 12 '10 at 16:43
  • 2
    Konrad, .NET has type inference, it knows what you're talking about even if you don't explicitly state it, for example, many functions on IEnumerable are generic type functions and yet you often don't have to specify the diamond operator because .NET infers its generic type. I really wish Java could be that smart. Also, in .NET you can simply call `default(T);` or `Activator.CreateInstance(typeof(T));` – Felype Nov 27 '15 at 11:41
  • So how do things like ArrayList and HashMap work - they instantiate instances of your T class without having to know anything more about it? – Mikepote Feb 05 '16 at 15:13
  • 4
    @Mikepote: they don't instantiate objects, they offer functionality to store references to already created objects. You don't let the `ArrayList` create a T instance, you just store a T reference that you allocated previously. – Jack Feb 05 '16 at 15:36
  • Actually .Net doesn't know what T represents exactly at compile time either, but it does at runtime, so `Type genericType = typeof(T)` makes perfect sense in .net, that will be resolved at runtime and the compiler won't bother at all with that line. Now from what I debugged here, it seems like Java doesn't even know at runtime what T represents, like, at all. – Felype Sep 09 '17 at 23:14
8

You need to get the type information statically. Try this:

public class Abc<T> {
    private Class<T> clazz;

    public Abc(Class<T> clazz) {
        this.clazz = clazz;
    }

    public T getInstanceOfT()
            throws throws InstantiationException,
                 IllegalAccessException,
                 IllegalArgumentException,
                 InvocationTargetException,
                 NoSuchMethodException,
                 SecurityException {
        return clazz.getDeclaredConstructor().newInstance();
    }
}

Use it as such:

        Abc<String> abc = new Abc<String>(String.class);
        abc.getInstanceOfT();

Depending on your needs, you may want to use Class<? extends T> instead.

Hosam Aly
  • 41,555
  • 36
  • 141
  • 182
  • 2
    [`clazz.newInstance()` is deprecated as of Java 9](https://docs.oracle.com/javase/9/docs/api/java/lang/Class.html#newInstance--): _can be replaced by `clazz.getDeclaredConstructor().newInstance()`_. – Gerold Broser Jun 11 '20 at 12:53
  • 1
    Thank you for the heads up, @GeroldBroserreinstatesMonica. I updated the example. – Hosam Aly Jun 12 '20 at 15:36
5

The only way to get it to work is to use Reified Generics. And this is not supported in Java (yet? it was planned for Java 7, but has been postponed). In C# for example it is supported assuming that T has a default constructor. You can even get the runtime type by typeof(T) and get the constructors by Type.GetConstructor(). I don't do C# so the syntax may be invalid, but it roughly look like this:

public class Foo<T> where T:new() {
    public void foo() {
        T t = new T();
    }
}

The best "workaround" for this in Java is to pass a Class<T> as method argument instead as several answers already pointed out.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Is adding *Reified Generics* to Java closed? https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8061418 – Ori Marko Dec 20 '18 at 10:02
4

First of all, you can't access the type parameter T in the static main method, only on non-static class members (in this case).

Second, you can't instantiate T because Java implements generics with Type Erasure. Almost all the generic information is erased at compile time.

Basically, you can't do this:

T member = new T();

Here's a nice tutorial on generics.

bruno conde
  • 47,767
  • 15
  • 98
  • 117
  • "First of all, you can't access the type parameter T in the static main method, only on non-static class members (in this case)." --- Agreed--- So I have updated the code to have a non-static method But the rest of the reasons are not much relevant. – Mohd Farid Mar 12 '10 at 17:06
2

You don't seem to understand how Generics work. You may want to look at http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html Basically what you could do is something like

public class Abc<T>
{
  T someGenericThing;
  public Abc(){}
  public T getSomeGenericThing()
  {
     return someGenericThing;
  }

  public static void main(String[] args)
  {
     // create an instance of "Abc of String"
        Abc<String> stringAbc = new Abc<String>();
        String test = stringAbc.getSomeGenericThing();
  }

} 
Tedil
  • 1,935
  • 28
  • 32
  • 11
    +1 You have perfectly narrated the problem. only thing missing is... Where are we initialising someGenericThing? – Mohd Farid Mar 12 '10 at 16:30
  • Agree with Mohd, stringAbc.getSomeGenericThing() is actually null. – eric2323223 Mar 15 '10 at 15:53
  • yeah, well, I forgot to add that bit. You would of course have to set/initialize some T you'd like, e.g. in the Abc constructor. Or via Setter Methods. But Mohd problem isn't about what I posted anyways (at least after he posted some comments) – Tedil Mar 15 '10 at 16:11
1

I was implementing the same using the following approach.

public class Abc<T>
{
   T myvar;

    public T getInstance(Class<T> clazz) throws InstantiationException, IllegalAccessException
    {
        return clazz.newInstance();
    }
}

I was trying to find a better way to achieve the same.

Isn't it possible?

Mohd Farid
  • 2,010
  • 1
  • 17
  • 23
  • 2
    This is better done by receiving `clazz` in the constructor (check my answer). If you do it in a method then it's almost meaningless, since it's just a shortcut for calling `someObject.getClass().newInstance()`, which doesn't seem to add much. Even if you decide to do it that way, you don't need a generic class; a static generic method would suffice. – Hosam Aly Mar 12 '10 at 17:09
  • [`clazz.newInstance()` is deprecated as of Java 9](https://docs.oracle.com/javase/9/docs/api/java/lang/Class.html#newInstance--): _can be replaced by `clazz.getDeclaredConstructor().newInstance()`_. – Gerold Broser Jun 11 '20 at 12:52
1

Type Erasure Workaround

Inspired by @martin's answer, I wrote a helper class that allows me to workaround the type erasure problem. Using this class (and a little ugly trick) I'm able to create a new instance out of a template type:

public abstract class C_TestClass<T > {
    T createTemplateInstance() {
        return C_GenericsHelper.createTemplateInstance( this, 0 );
    }

    public static void main( String[] args ) {
        ArrayList<String > list = 
            new C_TestClass<ArrayList<String > >(){}.createTemplateInstance();
    }
}

The ugly trick here is to make the class abstract so the user of the class is forced to subtype it. Here I'm subclassing it by appending {} after the call to the constructor. This defines a new anonymous class and creates an instance of it.

Once the generic class is subtyped with concrete template types, I'm able to retrieve the template types.


public class C_GenericsHelper {
    /**
     * @param object instance of a class that is a subclass of a generic class
     * @param index index of the generic type that should be instantiated
     * @return new instance of T (created by calling the default constructor)
     * @throws RuntimeException if T has no accessible default constructor
     */
    @SuppressWarnings( "unchecked" )
    public static <T> T createTemplateInstance( Object object, int index ) {
        ParameterizedType superClass = 
            (ParameterizedType )object.getClass().getGenericSuperclass();
        Type type = superClass.getActualTypeArguments()[ index ];
        Class<T > instanceType;
        if( type instanceof ParameterizedType ) {
            instanceType = (Class<T > )( (ParameterizedType )type ).getRawType();
        }
        else {
            instanceType = (Class<T > )type;
        }
        try {
            return instanceType.newInstance();
        }
        catch( Exception e ) {
            throw new RuntimeException( e );
        }
    }
}
Community
  • 1
  • 1
tangens
  • 39,095
  • 19
  • 120
  • 139
  • [`clazz.newInstance()` is deprecated as of Java 9](https://docs.oracle.com/javase/9/docs/api/java/lang/Class.html#newInstance--): _can be replaced by `clazz.getDeclaredConstructor().newInstance()`_. – Gerold Broser Jun 11 '20 at 12:51
1

There are hacky ways around this when you really have to do it.

Here's an example of a transform method that I find very useful; and provides one way to determine the concrete class of a generic.

This method accepts a collection of objects as input, and returns an array where each element is the result of calling a field getter on each object in the input collection. For example, say you have a List<People> and you want a String[] containing everyone's last name.

The type of the field value returned by the getter is specified by the generic E, and I need to instantiate an array of type E[] to store the return value.

The method itself is a bit ugly, but the code you write that uses it can be so much cleaner.

Note that this technique only works when somewhere in the input arguments there is an object whose type matches the return type, and you can deterministically figure it out. If the concrete classes of your input parameters (or their sub-objects) can tell you nothing about the generics, then this technique won't work.

public <E> E[] array (Collection c) {
    if (c == null) return null;
    if (c.isEmpty()) return (E[]) EMPTY_OBJECT_ARRAY;
    final List<E> collect = (List<E>) CollectionUtils.collect(c, this);
    final Class<E> elementType = (Class<E>) ReflectionUtil.getterType(c.iterator().next(), field);
    return collect.toArray((E[]) Array.newInstance(elementType, collect.size()));
}

Full code is here: https://github.com/cobbzilla/cobbzilla-utils/blob/master/src/main/java/org/cobbzilla/util/collection/FieldTransformer.java#L28

cobbzilla
  • 1,920
  • 1
  • 16
  • 17
0

It looks like you are trying to create the class that serves as the entry point to your application as a generic, and that won't work... The JVM won't know what type it is supposed to be using when it's instantiated as you start the application.

However, if this were the more general case, then something like would be what you're looking for:

public MyGeneric<MyChoiceOfType> getMeAGenericObject(){
   return new MyGeneric<MyChoiceOfType>();
}

or perhaps:

MyGeneric<String> objMyObject = new MyGeneric<String>();
Martin Milan
  • 6,346
  • 2
  • 32
  • 44
-3
Abc<String> abcInstance = new Abc<String> ();

..for example

Roman
  • 64,384
  • 92
  • 238
  • 332