168

I know Java's generics are somewhat inferior to .Net's.

I have a generic class Foo<T>, and I really need to instantiate a T in Foo using a parameter-less constructor. How can one work around Java's limitation?

arshajii
  • 127,459
  • 24
  • 238
  • 287
ripper234
  • 222,824
  • 274
  • 634
  • 905

10 Answers10

188

One option is to pass in Bar.class (or whatever type you're interested in - any way of specifying the appropriate Class<T> reference) and keep that value as a field:

public class Test {
    public static void main(String[] args) throws IllegalAccessException,
            InstantiationException {
        Generic<Bar> x = new Generic<>(Bar.class);
        Bar y = x.buildOne();
    }
}

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

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

    public T buildOne() throws InstantiationException, IllegalAccessException {
        return clazz.newInstance();
    }
}

public class Bar {
    public Bar() {
        System.out.println("Constructing");
    }
}

Another option is to have a "factory" interface, and you pass a factory to the constructor of the generic class. That's more flexible, and you don't need to worry about the reflection exceptions.

improbable
  • 2,308
  • 2
  • 15
  • 28
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Why not pass `new Foo()` as argument? – fastcodejava Mar 12 '10 at 12:04
  • 2
    @fastcodejava, because you need to pass Class type. Foo and Class are different types. – Özgür Mar 12 '10 at 14:54
  • What if the T type is a generic type in itself in the above example? Do we have to compromise with raw type then? – aayoustic Mar 26 '21 at 05:24
  • @AayushShrivastava: I don't *think* so - but it's been quite a few years since I've written Java regularly, to be honest. – Jon Skeet Mar 26 '21 at 06:53
  • Thank you. This It is exactly what i am looking for! – Manolis P. Aug 03 '21 at 18:34
  • Hello ! I created a topic on a related topic [link] (https://stackoverflow.com/questions/68685234/initialize-a-bounded-generic-type-java) regarding a initialization of a bounded generics trying to use Supplier, initially I have tried to use this alternative but then I thought that maybe for my case the Supplier Interface would be better. Would love to hear your ideas. Thanks – DTK Aug 06 '21 at 17:11
51

And this is the Factory implementation, as Jon Skeet suggested:

interface Factory<T> {
    T factory();
}

class Araba {
    //static inner class for Factory<T> implementation
    public static class ArabaFactory implements Factory<Araba> {
        public Araba factory() {
            return new Araba();
        }
    }
    public String toString() { return "Abubeee"; }
}

class Generic<T> {
    private T var;

    Generic(Factory<T> fact) {
        System.out.println("Constructor with Factory<T> parameter");
        var = fact.factory();
    }
    Generic(T var) {
        System.out.println("Constructor with T parameter");
        this.var = var;
    }
    T get() { return var; }
}

public class Main {
    public static void main(String[] string) {
        Generic<Araba> gen = new Generic<Araba>(new Araba.ArabaFactory());
        System.out.print(gen.get());
    }
}

Output:

Constructor with Factory<T> parameter
Abubeee
Community
  • 1
  • 1
Özgür
  • 8,077
  • 2
  • 68
  • 66
  • This is all great and all ... it certainly works. But ... if all we need is a new Bar instance (since `` is ``) then reflectively making a Bar instance with `Class token = Bar.class;` and `Bar newBar = token.newInstance();` appears so much less verbose to me. – scottb Aug 15 '13 at 20:25
  • 2
    @scottb: You may not have a simple class which can be created with a no-args constructor. In that case, a factory would be a more reliable solution than reflective class instantiation. – codethulhu Aug 15 '13 at 20:45
  • @codethulhu: Granted. However one of the stipulations of the original question was his intention to use a 'parameter-less constructor'. – scottb Aug 15 '13 at 21:09
7

Here's a rather contrived way to do it without explicitly using an constructor argument. You need to extend a parameterized abstract class.

public class Test {   
    public static void main(String [] args) throws Exception {
        Generic g = new Generic();
        g.initParameter();
    }
}

import java.lang.reflect.ParameterizedType;
public abstract class GenericAbstract<T extends Foo> {
    protected T parameter;

    @SuppressWarnings("unchecked")
    void initParameter() throws Exception, ClassNotFoundException, 
        InstantiationException {
        // Get the class name of this instance's type.
        ParameterizedType pt
            = (ParameterizedType) getClass().getGenericSuperclass();
        // You may need this split or not, use logging to check
        String parameterClassName
            = pt.getActualTypeArguments()[0].toString().split("\\s")[1];
        // Instantiate the Parameter and initialize it.
        parameter = (T) Class.forName(parameterClassName).newInstance();
    }
}

public class Generic extends GenericAbstract<Foo> {
}

public class Foo {
    public Foo() {
        System.out.println("Foo constructor...");
    }
}
Glenn
  • 6,455
  • 4
  • 33
  • 42
  • okay, i see. you can even write it more simply as an anonymous class: "GenericAbstract g = new GenericAbstract() { }; g.initParameter();" and the "" isn't necessary, just "" will do. but it still seems kinda useless to me, just a convoluted way of passing Foo.class to the object by declaring another class – newacct Jul 27 '09 at 02:19
  • @newacct actually I think it can help me create a BuffedArrayList that will finally help me avoid that obnoxious toArray(new Something[0]), so I can have a `T toArray()` hasslelessly! – Aquarius Power Nov 17 '16 at 19:10
  • @Glenn it works for ArrayList too but I have to instantiate like this: `new ArrayList(){}` no idea why tho... – Aquarius Power Nov 17 '16 at 23:12
4

I really need to instantiate a T in Foo using a parameter-less constructor

Simple answer is "you cant do that" java uses type erasure to implment generics which would prevent you from doing this.

How can one work around Java's limitation?

One way (there could be others) is to pass the object that you would pass the instance of T to the constructor of Foo<T>. Or you could have a method setBar(T theInstanceofT); to get your T instead of instantiating in the class it self.

dfa
  • 114,442
  • 31
  • 189
  • 228
hhafez
  • 38,949
  • 39
  • 113
  • 143
2

From https://stackoverflow.com/a/2434094/848072. You need a default constructor for T class.

import java.lang.reflect.ParameterizedType;

class Foo<T> {
  
  public bar() {
    ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass();
    Class<T> type = (Class<T>) superClass.getActualTypeArguments()[0];
    try {
      T t = (T) type.getDeclaredConstructor().newInstance();
      //Do whatever with t
    } catch (Exception e) {
      // Oops, no default constructor
      throw new RuntimeException(e);
    } 
  }
}
lepe
  • 24,677
  • 9
  • 99
  • 108
albfan
  • 12,542
  • 4
  • 61
  • 80
2

For Java 8 ....

There is a good solution at https://stackoverflow.com/a/36315051/2648077 post.

This uses Java 8 Supplier functional interface

Alireza Fattahi
  • 42,517
  • 14
  • 123
  • 173
2

Use The Constructor.newInstance method. The Class.newInstance method has been deprecated since Java 9 to enhance compiler recognition of instantiation exceptions.

public class Foo<T> {   
    public Foo()
    {
        Class<T> newT = null; 
        instantiateNew(newT);
    }

    T instantiateNew(Class<?> clsT)
    {
        T newT;
        try {
            newT = (T) clsT.getDeclaredConstructor().newInstance();
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
            | InvocationTargetException | NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
        return newT;
    }
}
1

Generics in Java are generally more powerful than in C#.

If you want to construct an object but without hardwiring a constructor/static method, use an abstract factory. You should be able to find detailed information and tutorials on the Abstract Factory Pattern in any basic design patterns book, introduction to OOP or all over the interwebs. It's not worth duplicating code here, other than to mention that Java's closure syntax sucks.

IIRC, C# has a special case for specifying a generic type has a no-args constructor. This irregularity, by definition, presupposes that client code wants to use this particular form of construction and encourages mutability.

Using reflection for this is just wrongheaded. Generics in Java are a compile-time, static-typing feature. Attempts to use them at runtime are a clear indication of something going wrong. Reflection causes verbose code, runtime failures, unchecked dependencies and security vulnerabilities. (Class.forName is particularly evil.)

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • 11
    "Generics in Java are generally more powerful than in C#" wut. They're not even reified. – wchargin Jun 06 '13 at 21:42
  • @WChargin: Yes, that's why the Java generics guarantee of type safety requires that your code compiles without errors or any warnings. If your code generates no warnings, you are guaranteed that your code is type safe without any overhead of run-time type checking. Whether Java generics are 'better' or not depends on whether you're a class half-full or glass half-empty sort of guy. – scottb Aug 15 '13 at 20:31
1

I could do this in a JUnit Test Setup.

I wanted to test a Hibernate facade so I was looking for a generic way to do it. Note that the facade also implements a generic interface. Here T is the database class and U the primary key. Ifacade<T,U> is a facade to access the database object T with the primary key U.

public abstract class GenericJPAController<T, U, C extends IFacade<T,U>>

{
    protected static EntityManagerFactory emf;

    /* The properties definition is straightforward*/
    protected T testObject;
    protected C facadeManager;

    @BeforeClass
    public static void setUpClass() {


        try {
            emf = Persistence.createEntityManagerFactory("my entity manager factory");

        } catch (Throwable ex) {
            System.err.println("Failed to create sessionFactory object." + ex);
            throw new ExceptionInInitializerError(ex);
        }

    }

    @AfterClass
    public static void tearDownClass() {
    }

    @Before
    public void setUp() {
    /* Get the class name*/
        String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[2].getTypeName();

        /* Create the instance */
        try {
            facadeManager = (C) Class.forName(className).newInstance();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
            Logger.getLogger(GenericJPAController.class.getName()).log(Level.SEVERE, null, ex);
        }
        createTestObject();
    }

    @After
    public void tearDown() {
    }

    /**
     * Test of testFindTEntities_0args method, of class
     * GenericJPAController<T, U, C extends IFacade<T,U>>.
     * @throws java.lang.ClassNotFoundException
     * @throws java.lang.NoSuchMethodException
     * @throws java.lang.InstantiationException
     * @throws java.lang.IllegalAccessException
     */
    @Test
    public void  testFindTEntities_0args() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException {

        /* Example of instance usage. Even intellisense (NetBeans) works here!*/
        try {
            List<T> lista = (List<T>) facadeManager.findAllEntities();
            lista.stream().forEach((ct) -> {
                System.out.println("Find all: " + stringReport());
            });
        } catch (Throwable ex) {
            System.err.println("Failed to access object." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }


    /**
     *
     * @return
     */
    public abstract String stringReport();

    protected abstract T createTestObject();
    protected abstract T editTestObject();
    protected abstract U getTextObjectIndex();
}
Krauss
  • 998
  • 10
  • 17
0

Quick solution that worked for me. I see there is already an answer for this and this may not even be the best way to go about it. Also, for my solution you'll need Gson.

However, I ran into a situation where I needed to create an instance of a generic class of type java.lang.reflect.Type.

The following code will create an instance of the class you want with null instance variables.

T object = new Gson().fromJson("{}", myKnownType);

Where myKnownType is known before hand and obtained via TypeToken.getType().

You can now set appropriate properties on this object. Again, this may not be the best way to do this but it works as a quick solution if that's what you need.

Markymark
  • 2,804
  • 1
  • 32
  • 37