Related
I am looking to create a particular type of interface in Java (although this is just as applicable to regular classes). This interface would need to contain some method, say, invoke; it would be called with a varying amount of parameters depending on the generic type arguments supplied.
As an example:
public interface Foo<T...> {
public void invoke(T... args);
}
// In some other class
public static Foo<Float, String, Integer> bar = new Foo<Float, String, Integer>() {
#Override
public void invoke(Float arg1, String arg2, Integer arg3) {
// Do whatever
}
};
To explain, briefly, how this could be used (and provide some context), consider a class Delegator: the class takes a varying number of generic types, and has a single method - invoke, with these parameter types. The method passes on its parameters to an object in a list: an instance of IDelegate, which takes the same generic types. This allows Delegator to choose between several delegate methods (defined inside IDelegate) without having to create a new class for each specific list of parameter types.
Is anything like this available? I have read about variadic templates in C++, but cannot find anything similar in Java. Is any such thing available? If not, what would be the cleanest way to emulate the same data model?
Is anything like this available? I have read about variadic templates
in C++, but cannot find anything similar in Java. Is any such thing
available?
No, this feature is not available in Java.
No, there is nothing like that directly available. However if you use a library with Tuple classes you can simulate it by just making the interface
interface Foo<T> {
void invoke(T t);
}
(This interface is essentially the same as Consumer<T>.)
Then you could do for example
Foo<Tuple<String, Integer, Date, Long>> foo = new Foo<>() {
...
}
You would need a separate Tuple type for each number of parameters. If you have a Tuple class for 4 parameters, but not one for 5, you could squeeze an extra parameter in by using a Pair class.
Foo<Tuple<String, Integer, Date, Pair<Long, BigDecimal>>> foo = ...
By nesting tuple types in this way you get an unlimited number of parameters. However, these workarounds are really ugly, and I would not use them.
Given the context you provided I would recommend using a List as a parameter. If these parameters have something in common, you can restrain your list to <T extends CommonParrent> instead of using List<Object>. If not, you may still want to use marker interface.
Here is an example.
public class Main {
public static void main(String[] args) {
delegate(asList(new ChildOne(1), new ChildTwo(5), new ChildOne(15)));
}
private static <T extends Parent> void delegate(List<T> list) {
list.forEach(item -> {
switch (item.type) {
case ONE: delegateOne((ChildOne) item); break;
case TWO: delegateTwo((ChildTwo) item); break;
default: throw new UnsupportedOperationException("Type not supported: " + item.type);
}
});
}
private static void delegateOne(ChildOne childOne) {
System.out.println("child one: x=" + childOne.x);
}
private static void delegateTwo(ChildTwo childTwo) {
System.out.println("child two: abc=" + childTwo.abc);
}
}
public class Parent {
public final Type type;
public Parent(Type type) {
this.type = type;
}
}
public enum Type {
ONE, TWO
}
public class ChildOne extends Parent {
public final int x;
public ChildOne(int x) {
super(Type.ONE);
this.x = x;
}
}
public class ChildTwo extends Parent {
public final int abc;
public ChildTwo(int abc) {
super(Type.TWO);
this.abc = abc;
}
}
The biggest flaw of this solution is that children have to specify their type via enum which should correspond to the casts in the switch statement, so whenever you change one of these two places, you will have to remember to change the other, because compiler will not tell you this. You will only find such mistake by running the code and executing specific branch so test driven development recommended.
I have a generic class in java defined as:
public static class KeyCountMap<T>
{
private Map<T, MutableInt> map = new LinkedHashMap<T, MutableInt>();
// ... rest of the properties...
public KeyCountMap()
{ }
#SuppressWarnings({ "unchecked", "rawtypes" })
public KeyCountMap(Class<? extends Map> mapType) throws InstantiationException, IllegalAccessException
{
map = mapType.newInstance();
}
//... rest of the methods...
}
I have defined same class in .NET as:
public static class KeyCountMap<T>
{
private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
// ... rest of properties...
public KeyCountMap()
{ }
public void KeyCountMap<T>(T obj) where T : Dictionary<T, MutableInt>
{
obj = new T(); // Unable to define new instance of T
map = obj; // Unable to convert T to base class
}
}
And then a method is defined to sort map of type KeyCountMap<T> by value in the descending order . The method is defined as:
public static KeyCountMap<T> SortMapByDescendValue<T>(KeyCountMap<T> _map)
{
List<KeyValuePair<T, MutableInt>> _list = new List<KeyValuePair<T, MutableInt>>(_map.EntrySet());
// whereas _map.EntrySet() return of type HashSet<KeyValuePair<T, MutableInt>>
_list = _list.OrderByDescending(_x => _x.Value).ToList();
KeyCountMap<T> _result = new KeyCountMap<T>();
foreach (KeyValuePair<T, MutableInt> _entry in _list)
{
_result.Put(_entry.Key, _entry.Value);
}
return _result;
}
How can I get corrected the class defined in .NET ?
I assume you know Java erases any generic type information after compiling (there's metadata for variables, but actual objects are void of generic type information). Moreover, your code is not type safe:
#SuppressWarnings({ "unchecked", "rawtypes" })
You're using this because you're creating a non-parameterized instance of Map.
In .NET, you don't get around the type system like this, because generic type information is kept and used at runtime.
Let's see your C# code:
public static class KeyCountMap<T>
A static class in C# is a class that cannot be instanced, it's used for its static members alone. I think you don't want this. Perhaps KeyCountMap is a static nested class in Java, as opposed to an inner class.
In C#, you don't have inner classes. Nested classes don't share data with an instance of the containing class, it's as if the name of the containing class is part of the namespace for the nested class. So, you don't need, and actually don't want, the static keyword here.
{
private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
In .NET, Dictionary is a class. To keep the intent, you should use IDictionary, the corresponding interface, as the type for the map field.
// ... rest of properties...
public KeyCountMap()
{ }
public void KeyCountMap<T>(T obj) where T : Dictionary<T, MutableInt>
Why the void return type, isn't this a constructor?
In C#, constructors can't be generic. You probably want a Type.
Your C# code just doesn't make sense, so here's what you could do:
public KeyCountMap(Type dictionaryType)
{
if (!typeof(IDictionary<T, MutableInt>).IsAssignableFrom(dictionaryType))
{
throw new ArgumentException("Type must be a IDictionary<T, MutableInt>", nameof(dictionaryType));
}
map = (IDictionary<T, MutableInt>)Activator.CreateInstance(dictionaryType);
}
}
We're checking the type before creating an instance. If we didn't, we would create an instance, the cast would fail and the assignment wouldn't even happen, so the new instance would just be garbage.
It may be that the actual instance will be a proxy; if so, you may not want to check the type before creating an instance.
You can't just copy-paste Java as C# (or vice-versa) and expect to make just a few changes until it works, for some definition of works, e.g. it compiles. The languages are not that similar, and chances are that too many subtle things are wrong.
This approach might be fun at first, but you'll stumble so often it will soon stop being any fun at all. You should learn the basics and understand the way things are done in the target language before you start translating code line-by-line. Many times, you may find that something you had to do in one environment already exists in the other or vice-versa, or that something may take more or less steps to do in the other, etc.
In this particular case, Java made Class be a generic class, while .NET kept Type a non-generic class. In .NET only interfaces and delegates may state generic type covariance or contravariance. This is rather restrictive anyway, if Type was generic, the intended uses could be either covariant or contravariant. But remember that in Java, a generic Class<T> at runtime is as good as Class, it only has any value at compile time and you can tell the compiler you know better anyway, just like you did.
There are two problems. First, you need to tell the compiler that T has a parameterless constructor, so you can call new T(). You can do that by providing the new() argument to the class definition.
You also have to tell the compiler that T is actually the dictionary you are trying to assign, so we have to extend the class a little more:
public class KeyCountMap<K>
{
private Dictionary<K, MutableInt> map = new Dictionary<K, MutableInt>();
// ... rest of properties...
Note that K is the key type of the dictionary, which you didn't specify yet.
Second, the T in your method can be another T than in your class. Omitting that will do the trick:
public void Map()
{
var obj = new Dictionary<K, MutableInt>(); // Unable to define new instance of T
map = obj; // Unable to convert T to base class
}
Maybe this is what you want?
public class KeyCountMap<T>
where T : new()
{
private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
// ... rest of properties...
public KeyCountMap()
{ }
public KeyCountMap(T obj)
{
obj = new T();
map = (Dictionary<T, MutableInt>)(object)obj;
}
}
I searched and tried now for more than a day and could not find a solution for a common problem I have in Java. The reason is obvious - Type erasure. But the question I have is: Is there really no good solution for this problem in Java? I am willing to investigate even more time since this kind of problem pops up every once in a time.
The error I get is:
The method doStrategy(capture#2-of ? extends I) in the type IStrategy<capture#2-of ? extends I> is not applicable for the arguments (I)
So I simplified the problem to the following example.
Imagine the model:
package model;
public interface I {
//there are actual 30 classes implementing I...
}
public class A implements I {
public void someSpecificMagicForA(){
System.out.println("A");
}
}
public class B implements I {
public void someSpecificMagicForB() {
System.out.println("B");
}
}
and the selection logic
package strategy;
import model.A;
public interface IStrategy<T> {
public void doStrategy(T t);
}
public class AStrategy implements IStrategy<A> {
#Override
public void doStrategy(A a) {
a.someSpecificMagicForA();
}
}
public class BStrategy implements IStrategy<B> {
#Override
public void doStrategy(B b) {
b.someSpecificMagicForB();
}
}
and a generic strategy factory
package strategy;
import java.util.HashMap;
import java.util.Map;
import model.A;
import model.B;
public class StrategyFactory {
static {
strategies.put(A.class, AStrategy.class);
strategies.put(B.class, BStrategy.class);
}
private static final Map<Class<?>, Class<? extends IStrategy<?>>> strategies = new HashMap<>();
#SuppressWarnings("unchecked") // I am fine with that suppress warning
public <T> IStrategy<T> createStategy(Class<T> clazz){
Class<? extends IStrategy<?>> strategyClass = strategies.get(clazz);
assert(strategyClass != null);
try {
return (IStrategy<T>) strategyClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
return null;
}
}
}
And here is the test
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import model.A;
import model.B;
import model.I;
import strategy.IStrategy;
import strategy.StrategyFactory;
public class TestCases extends TestCase {
public void testWithConcreteType(){
B b = new B();
StrategyFactory factory = new StrategyFactory();
IStrategy<B> createStategy = factory.createStategy(B.class);
createStategy.doStrategy(b); //awesome
}
public void testWithGenericType(){
List<I> instances = createTestData(); // image this is the business data
StrategyFactory factory = new StrategyFactory();
for (I current : instances){
IStrategy<? extends I> createStategy = factory.createStategy(current.getClass());
createStategy.doStrategy(current); //meh
//The method doStrategy(capture#2-of ? extends I) in the type IStrategy<capture#2-of ? extends I>
//is not applicable for the arguments (I)
}
}
private List<I> createTestData(){
A a = new A();
B b = new B();
List<I> instances = new ArrayList<>();
instances.add(a);
instances.add(b);
return instances;
}
}
I have tried another approach using guava TypeTokens (https://github.com/google/guava/wiki/ReflectionExplained). But I did not manage to get this working since I really have no <T> since all I get is that Collection of instances implementing that interface.
I have a working and not so bad solution though using the Visitor-pattern. Since I there have the real classes
...visitor class
public void visit(A a){
doVisit(A.class, a); //private generic method now works of course
}
everything is fine again at compile time. But in this particular case it took me quite some time to implement that visitor for more than 30 sub-classes of I. So I would really like to have a better solution for the future.
Any comments are much appreciated.
The problem has nothing to do with erasure. It is that Java's type system is not strong enough to reason statically about the relationship between current and current.getClass() without some help.
In your code:
for (I current : instances){
IStrategy<? extends I> createStategy = factory.createStategy(current.getClass());
createStategy.doStrategy(current);
}
the result of current.getClass() is an object of type Class<? extends I>; that is, some subtype of I that we don't know statically. We the programmers know that whatever type it is, that's also the concrete type of current because we've read the documentation for getClass, but the type system doesn't know that. So when we get an IStrategy<? extends I>, all we know is that it's a strategy that works on some subtype of I, not necessarily I itself. Add to that the fact that wildcard types (the types with ?) are designed to lose even more information, and so the type system doesn't even know that our strategy accepts the same type as the result of getClass().
So to make the program typecheck, we need to (a) give the type system some non-wildcard name for the specific subtype of I that current is, and (b) convince it that the value of current actually has that type. The good news is, we can do both.
To give a name to a wildcard type, we can use a technique called "wildcard capture", where we create a private helper function whose only job is to give a specific type variable name to a type that would otherwise be a wildcard. We'll pull out the body of the test loop into its own function that critically takes a type parameter:
private <T> void genericTestHelperDraft1(Class<T> currentClass, T current) {
StrategyFactory factory = new StrategyFactory();
IStrategy<T> createStrategy = factory.createStategy(t);
createStrategy.doStrategy(current); // works
}
The job of this function is effectively to introduce the type parameter T, which lets Java know that we intend to refer to the same unknown type T everywhere we use it. With that information it can understand that the strategy we get from our factory works on the same type that our input class has, which is the same type current current has in the type signature.
Unfortunately, when we go to call this method we'll still get a compile error:
for (I current : instances){
genericTestHelperDraft1(current.getClass(), current);
// Type error because current is not of type "capture of ? extends I"
}
The problem here is that the type system doesn't know that current has its own type! Java's type system doesn't understand the relationship between current and current.getClass(), so it doesn't know that whatever type current.getClass() returns, we can treat current as a value of that type. Fortunately we can fix that with a simple downcast, since we (the programmers) do know that current has its own type. We have to do this within our helper, since outside the helper we don't have any name for the subtype we want to assert that current has. We can change the code like so:
private <T> void genericTestHelperDraft2(Class<T> t, Object current) {
T currentDowncast = t.cast(current);
StrategyFactory factory = new StrategyFactory();
IStrategy<T> createStrategy = factory.createStategy(t);
createStrategy.doStrategy(currentDowncast);
}
Now we can change the loop within the test to:
for (I current : instances){
genericTestHelperDraft2(current.getClass(), current);
}
and everything works.
Generic is a compile time feature and you can only work with what the compiler can determine as safe.
Note the type is not erased in all cases. You can get the type of AStrategy and BStrategy for example as these are concrete types which are not dynamic.
AStrategy as = new AStrategy();
for(AnnotatedType asc : as.getClass().getAnnotatedInterfaces()) {
Type type = asc.getType();
System.out.println(type);
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
for (Type t : pt.getActualTypeArguments()){
System.out.println(t); // class A
}
}
}
prints
IStrategy<A>
class A
whether all this code makes your solution simpler, I don't know but you can get the type of IStrategy which is being implemented provided it is known when the class was compiled.
After Peter´s answer and some more research I am pretty sure this is not possible in Java without enhancing the model in one way or another. I decided to stay with the Visitor-pattern since the compile time checks are worth the extra code in my opinion.
So here is what I implemented in the end (also I´m sure you all know the Visitor-pattern - just to be complete).
public interface I {
public void acceptVisitor(IVisitor visitor);
//there are actual 30 classes implementing I...
}
public interface IVisitor {
public void visit(A a);
public void visit(B b);
}
public void testWithGenericType(){
List<I> instances = createTestData(); // image this is the business data
StrategyFactory factory = new StrategyFactory();
Visitor visitor = new Visitor(factory);
for (I current : instances){
current.acceptVisitor(visitor);
}
}
class Visitor implements IVisitor {
private final StrategyFactory factory;
public Visitor(StrategyFactory factory) {
this.factory = factory;
}
private <T> void doVisit(Class<T> clazz, T t){
IStrategy<T> createStategy = factory.createStategy(clazz);
createStategy.doStrategy(t);
}
#Override
public void visit(A a) {
doVisit(A.class, a);
}
#Override
public void visit(B b) {
doVisit(B.class, b);
}
}
Hope this maybe helps someone else.
Regards,
Rainer
I am looking to create a particular type of interface in Java (although this is just as applicable to regular classes). This interface would need to contain some method, say, invoke; it would be called with a varying amount of parameters depending on the generic type arguments supplied.
As an example:
public interface Foo<T...> {
public void invoke(T... args);
}
// In some other class
public static Foo<Float, String, Integer> bar = new Foo<Float, String, Integer>() {
#Override
public void invoke(Float arg1, String arg2, Integer arg3) {
// Do whatever
}
};
To explain, briefly, how this could be used (and provide some context), consider a class Delegator: the class takes a varying number of generic types, and has a single method - invoke, with these parameter types. The method passes on its parameters to an object in a list: an instance of IDelegate, which takes the same generic types. This allows Delegator to choose between several delegate methods (defined inside IDelegate) without having to create a new class for each specific list of parameter types.
Is anything like this available? I have read about variadic templates in C++, but cannot find anything similar in Java. Is any such thing available? If not, what would be the cleanest way to emulate the same data model?
Is anything like this available? I have read about variadic templates
in C++, but cannot find anything similar in Java. Is any such thing
available?
No, this feature is not available in Java.
No, there is nothing like that directly available. However if you use a library with Tuple classes you can simulate it by just making the interface
interface Foo<T> {
void invoke(T t);
}
(This interface is essentially the same as Consumer<T>.)
Then you could do for example
Foo<Tuple<String, Integer, Date, Long>> foo = new Foo<>() {
...
}
You would need a separate Tuple type for each number of parameters. If you have a Tuple class for 4 parameters, but not one for 5, you could squeeze an extra parameter in by using a Pair class.
Foo<Tuple<String, Integer, Date, Pair<Long, BigDecimal>>> foo = ...
By nesting tuple types in this way you get an unlimited number of parameters. However, these workarounds are really ugly, and I would not use them.
Given the context you provided I would recommend using a List as a parameter. If these parameters have something in common, you can restrain your list to <T extends CommonParrent> instead of using List<Object>. If not, you may still want to use marker interface.
Here is an example.
public class Main {
public static void main(String[] args) {
delegate(asList(new ChildOne(1), new ChildTwo(5), new ChildOne(15)));
}
private static <T extends Parent> void delegate(List<T> list) {
list.forEach(item -> {
switch (item.type) {
case ONE: delegateOne((ChildOne) item); break;
case TWO: delegateTwo((ChildTwo) item); break;
default: throw new UnsupportedOperationException("Type not supported: " + item.type);
}
});
}
private static void delegateOne(ChildOne childOne) {
System.out.println("child one: x=" + childOne.x);
}
private static void delegateTwo(ChildTwo childTwo) {
System.out.println("child two: abc=" + childTwo.abc);
}
}
public class Parent {
public final Type type;
public Parent(Type type) {
this.type = type;
}
}
public enum Type {
ONE, TWO
}
public class ChildOne extends Parent {
public final int x;
public ChildOne(int x) {
super(Type.ONE);
this.x = x;
}
}
public class ChildTwo extends Parent {
public final int abc;
public ChildTwo(int abc) {
super(Type.TWO);
this.abc = abc;
}
}
The biggest flaw of this solution is that children have to specify their type via enum which should correspond to the casts in the switch statement, so whenever you change one of these two places, you will have to remember to change the other, because compiler will not tell you this. You will only find such mistake by running the code and executing specific branch so test driven development recommended.
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.
}
}
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.
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>
{
}
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.
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.
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.
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.
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();
}
}
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?
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 );
}
}
}
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
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>();
Abc<String> abcInstance = new Abc<String> ();
..for example