使用<t> </t>进行通用方法调用

时间:2013-02-12 18:12:33

标签: java generics jls

我在理解这种泛型方法调用时遇到问题:

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

以上是上述情况的背景:

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;
   }
}

问题是在<T>调用之前,getObject(objectName)扮演什么角色?

5 个答案:

答案 0 :(得分:7)

注意:在您给出的具体示例中,ObjectGenerator.getObject(objectName);应该编译好。

在某些情况下,类型推断机制无法解决以下事实:

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

返回的类型应为T。在这种情况下,您需要通过显式指示您期望的返回类型为编译器提供一些帮助。

这是一个人为的例子,您需要明确指定泛型类型:

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;
    }
}

答案 1 :(得分:0)

object可以是T的孩子。

当然,最好定义getObject

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

否则就没有类型安全结构,因为所谓的类型擦除。

答案 2 :(得分:0)

我在这里找到了一些东西:https://stackoverflow.com/a/338906/443427它可以帮到你。

从我读到的内容可能代表编译器必须用来计算重新调整的值类型的泛型,以传递泛型前向

作为注释,这也可以正常工作(检查ObjectGenerator与T的不同):

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

答案 3 :(得分:0)

我并不完全同意接受的答案,其中说:

  

在这种情况下,您需要明确地给编译器一些帮助   表示您期望的返回类型。

这对我来说听起来不对。由于我理解泛型方法和类型推断,方括号中提供的类型不直接指示泛型方法的返回类型。相反,类型T可以是返回类型,参数类型,与泛型方法关联的局部变量类型。

实际上,由于类型推断机制,在大多数情况下我们不需要指定类型参数T(不仅在某些情况下)。在您的示例中,与大多数其他情况一样,可以在方法调用<T>中安全地省略ObjectGenerator.<T> getObject(objectName)。这是因为通用方法的类型T可以从分配结果的类型或返回轻松推断出来。换句话说,由于您在方法调用之前声明private T object,因此类型T将成功推断为T

我的声明可以通过a definitive tutorial中的以下声明进行备份:

  

类型推断是Java编译器查看每个方法的能力   调用和相应的声明来确定类型   使调用适用的参数(或参数)。该   推理算法确定参数的类型,如果   available,分配或返回结果的类型。   最后,推理算法试图找到最具体的类型   适用于所有论点。

关于推理如何工作的两个例子:

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

根据声明的受让人类型,类型T被推断为Serializable

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

类型U根据传递的参数的类型推断为Integer(即,Integer.valueOf(10)的类型为Integer)。因此,可以从上面的方法调用中安全地省略<Integer>

总结一下,除非我们无法从其参数类型或结果被分配或返回的类型(调用方法时)推断泛型方法的类型参数,否则我们可以安全地省略类型规范权限在方法调用之前。

答案 4 :(得分:-1)

 object = ObjectGenerator.getObject(objectName);

总是返回Object的对象,因为您正在调用静态方法。要在代码中显式获取用于T的通用对象,

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

<T>用于静态上下文。对于非静态调用,不需要它。