tags:

views:

193

answers:

4

How to write a generic method in Java.

In C# I would do this

    public static T Resolve<T>()
    {
        return (T) new object();
    }

Whats the equivalent in Java?

A: 

Try this http://java.sun.com/docs/books/tutorial/extra/generics/methods.html

 public static <T> T Resolve()
    {
        return (T) new Object();
    }

Be careful about (T) but I am not sure that this is correct. I know that generic cast causes a lot of problems. I have already spent with it a lot of time...

Gaim
Wouldn't this code throw `java.lang.ClassCastException` ?
missingfaktor
This works ok in Java because T is erased to Object at compile time. However you really aren't getting any type-safety out of this implementation.
Mike Q
@ GreyMatter 9: Right, the Resolve method provokes an java.lang.ClassCastException if T is any other type than java.lang.Object.
Frank Grimm
The CCE is actually thrown from the call site, not this method. (But that is pedantry.)
Tom Hawtin - tackline
+10  A: 

First, your C# example is wrong; it will throw an InvalidCastException unless typeof(T) == typeof(object). You can fix it by adding a constraint:

public static T Resolve() where T : new() {
    return new T();
}

Now, this would be the equivalent syntax in Java (or, at least, as close as we can get):

public static <T> T Resolve() {
    return (T) new T();
}

Notice the double mention of T in the declaration: one is the T in <T> which parameterizes the method, and the second is the return type T.

Unfortunately, the above does not work in Java. Because of the way that Java generics are implemented runtime type information about T is not available and so the above gives a compile-time error. Now, you can work around this constraint like so:

public static <T> T Resolve(Class<T> c) {
    return c.newInstance();
}

Note the need to pass in T.class. This is known as a runtime type token. It is the idiomatic way of handling this situation.

Jason
That's going to throw some exceptions! Don't use reflection in these cases.
Tom Hawtin - tackline
@tackline: No, this is idiomatic Java for handling this situation: cf. http://java.sun.com/docs/books/tutorial/extra/generics/literals.html
Jason
+1  A: 

As other commenters have pointed out, you can do this with Java as well - with as much of a possibility to create a casting exception at runtime:

@SuppressWarnings("unchecked")
public static <T> T resolve() {
  return (T) new Object();
}

Unless you use the @SuppressWarnings annotation, however, Java's type erasure comes into play and you will get a compiler warning. The exception will also occur somewhere else: whereever you are trying to use it:

String s = <String>resolve();

will throw the exception.

On the other hand, you probably wanted to use new T() in C# anyway. This you cannot do in Java. The suggested workaround is to use Class<T> as a type parameter if you need to rely on type information at runtime. For your example, this would mean that you have to refactor it to this version:

public static <T> T resolve(Class<T> type) {
  try {
    return type.newInstance();
  } catch(Exception e) {
    // deal with the exceptions that can happen if 
    // the type doesn't have a public default constructor
    // (something you could write as where T : new() in C#)
  }
}

By the way, you can use this also to get rid of the warning in the previous case and to place the runtime exception at a more sensible line:

public static <T> T resolve(Class<T> type) {
  return type.cast(new Object());
}

This piece of code will behave exactly like the one you gave as an example - including an exception that occurs when T is any type different from Object.

nd
A: 

You want some kind of factory:

 public interface MyFactory<T> {
     T newInstance();
 }

Then that can be passed into where it is needed. In your code:

public static T resolve<T>(MyFactory<T> factory) {
    return factory.newInstance();
}

Note: There is absolutely no reason to be using reflection for this!!

Tom Hawtin - tackline