Question

I have a problem with understanding such generic method invocation:

object = ObjectGenerator.<T> getObject(objectName);

Here comes a context for above situation:

class GenClass<T> {

   private T object;

   // ... some code

   public void initObject(String objectName) {
      object = ObjectGenerator.<T> getObject(objectName);
   }
}

class ObjectGenerator {

   public static <T extends Object> T getObject(String name) {
      // some code
      return someObject;
   }
}

The question is what role plays <T> before getObject(objectName) invocation?

Was it helpful?

Solution

Note: in the specific example you have given, ObjectGenerator.getObject(objectName); should compile fine.

In some situations, the type inference mechanism can't resolve the fact that in:

T object;
object = ObjectGenerator.getObject(objectName);

the returned type should be T. In such a case, you need give the compiler a little help by explicitly indicating the return type you expect.

Here is a contrived example where you need to explicitly specify the generic type:

class Example {
    public static <T> List<T> m1() {
        return m2(Arrays.<T> asList()); //Arrays.asList() would not compile
    }
    public static <T> List<T> m2(List<T> l) {
        return l;
    }
}

OTHER TIPS

object can be child of T.

Of course getObject should better have been defined:

public static <T> T getObject(Class<T> objectClass, String name) {
   return objectClass.getConstructor(String.class).newInstance(name);
   //return objectClass.getConstructor().newInstance();
}

otherwise there is no type safe construction possible, because of the so called type erasure.

I found somthing here: https://stackoverflow.com/a/338906/443427 it may help you.

From what i read may represent the generic that compiler must use to compute the retuned value type, to pass the generic forward

as a note this also work fine (check the ObjectGenerator differs from T):

public class ObjectGenerator<X> {
    public static <T extends Object> Set<T> getObject(String name) {
    // some code
    return null;
    }
}

I don't totally agree with the accepted answer, in which it says:

In such a case, you need give the compiler a little help by explicitly indicating the return type you expect.

This does not sound right to me. As I understand generic method and type inference, the type provided in square brackets does not directly indicate the return type of the generic method. Rather, the type T could be return type, argument type, local variable type associated with the generic method.

Actually, thanks to type inference mechanism, we do not need to specify the type parameter T in most cases(not only in some situations). In your example, the <T> can be safely omitted from the method invocation ObjectGenerator.<T> getObject(objectName) like in most other cases. This is because the type T of the generic method can be easily inferred from the type that the result is being assigned, or returned. In other words, since you declare private T object before the method invocation the type T will be successfully inferred as T.

My claim can be backed up by the following statement from a definitive tutorial:

Type inference is a Java compiler's ability to look at each method invocation and corresponding declaration to determine the type argument (or arguments) that make the invocation applicable. The inference algorithm determines the types of the arguments and, if available, the type that the result is being assigned, or returned. Finally, the inference algorithm tries to find the most specific type that works with all of the arguments.

Two examples regarding how the inference works:

static <T> T pick(T a1, T a2) { return a2; }
Serializable s = pick("d", new ArrayList<String>());

The type T is inferred as Serializable based on the declared assignee type.

public static <U> void addBox(U u, java.util.List<Box<U>> boxes) {}
BoxDemo.<Integer>addBox(Integer.valueOf(10), listOfIntegerBoxes);

The type U is inferred as Integer based on the type of the passed argument(i.e., Integer.valueOf(10) is of type Integer). Hence, the <Integer> can be safely omitted from the method invocation above.

To summarize, unless we are not able to infer the type parameter of the generic method from its argument type or the type that the result is being assigned or returned(when invoking the method), we can safely omit the type specification right before the method invocation.

 object = ObjectGenerator.getObject(objectName);

always returns Object's object since you are calling a static method. For explicitly getting the generic object you have used for T,in your code,

 object = ObjectGenerator.<T> getObject(objectName); 

<T> is used in static context. For non static invocation it is not needed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top