7

我对理解这种通用方法调用有疑问:

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)

4

5 回答 5

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;
    }
}
于 2013-02-12T18:24:12.860 回答
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();
}

否则就不可能有类型安全的构造,因为所谓的类型擦除。

于 2013-02-12T18:22:11.100 回答
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;
    }
}
于 2013-02-12T18:33:11.080 回答
0

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

在这种情况下,您需要通过显式指示您期望的返回类型来给编译器一点帮助。

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

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

我的主张可以得到权威教程中的以下声明的支持:

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

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

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

该类型TSerializable根据声明的受让人类型推断的。

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

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

总而言之,除非我们无法从泛型方法的实参类型或分配或返回结果的类型(调用方法时)推断出泛型方法的类型参数,否则我们可以安全地在方法之前省略类型说明调用。

于 2013-02-12T19:47:20.853 回答
-1
 object = ObjectGenerator.getObject(objectName);

由于您调用的是静态方法,因此始终返回 Object 的对象。为了在代码中显式获取您用于 T 的通用对象,

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

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

于 2013-02-12T18:24:46.180 回答