1

I asked this question over 10 years ago, about C#, and got a good answer there. Now I'm trying to do the same thing in Java.

Say I have an abstract class Animal. I want a static method create() in that class, that will return a value of the type of whatever the subclass is. I managed this in C# using the following structure:

public class Animal<T> where T : Animal<T>, new()
{
    public static T Create()
    {
        var t = new T();
        // do generic stuff on the new T instance
        return t;
    }
}

public class Dog : Animal<Dog>
{

}

//usage:
var dog = Dog.Create();

This worked a charm in C#. But now I'm trying to replicate this structure in Java, and hitting a wall. One big wall is that it seems that you can't have static generic members. So this would seem to be a bit of a showstopper. But I'm an optimistic kind of guy, and maybe some Java expert out there has come up with a totally out of the box pattern for achieving more or less what I'm trying to do here?

Shaul Behr
  • 36,951
  • 69
  • 249
  • 387
  • [Create instance of generic type in Java](https://stackoverflow.com/questions/75175/create-instance-of-generic-type-in-java) – Thiyagu Jun 18 '20 at 14:39
  • 1
    Does this answer your question? [Create instance of generic type in Java?](https://stackoverflow.com/questions/75175/create-instance-of-generic-type-in-java) – OH GOD SPIDERS Jun 18 '20 at 14:39

1 Answers1

0

Problem is that in Java you can't construct an instance off a type variable like that.

As a quick alternative, you can use factories that your code aids with a concrete constructor call

@FunctionalInterface
interface AnimalFactory<T extends Animal> {
    T create();

    static <U extends Animal> AnimalFactory<U> ofClass(Class<U> type) {
        return () -> {
            try {
                return type.newInstance();
            } catch (Exception e) {
                // handle
                throw new RuntimeException(e);
            }
        };
    }

    static <U extends Animal> AnimalFactory<U> ofSupplier(Supplier<U> creator) {
        return creator::get;
    }
}

Then you can call that in your Animal static methods (you can indeed reuse it for other types):

class Animal {
    static <T extends Animal> T create(Class<T> type) {
        T instance = AnimalFactory.ofClass(type)
                .create();
        // do generic stuff on the new T instance
        return instance;
    }

    static <T extends Animal> T create(Supplier<T> creator) {
        T instance = AnimalFactory.ofSupplier(creator)
                .create();
        // do generic stuff on the new T instance
        return instance;
    }
}

In the end, your calling code can look as below. I used a lambda and a reflection-based approaches. You pick.

Dog d = Animal.create(Dog.class);
Dog e = Animal.create(Dog::new);

Of course, you can skip the static methods in Animal altogether and use AnimalFactory directly (interfaces can now have static methods that you can use to run the // do generic stuff on the new T instance logic)

ernest_k
  • 44,416
  • 5
  • 53
  • 99