运行Demo类将调用SomeClass中的静态方法newInstance来调用构造函数并打印hello
定义方法将包含带参数
的返回类型+方法名称newInstance的返回类型是< T> SomeClass< T>对我来说似乎很奇怪 因为我的班级被称为SomeClass< T>而不是< T> SomeClass< T>
为什么我需要< T>在SomeClass< T>前面? 似乎如果我不包括它将会有一个常见的错误 called不能对非静态类型T
进行静态引用
要指出的另一件事是我可以在< T>之间放置许多空格了。和SomeClass< T>所以看起来他们不需要在一起。
public class SomeClass<T> {
public static <T>SomeClass<T> newInstance(Class<T> clazz){
return new SomeClass<T>(clazz);
}
private SomeClass(Class<T> clazz){
System.out.println("hello");
}
}
public class Demo {
public static void main(String args[])
{
SomeClass<String> instance = SomeClass.newInstance(String.class);
}
}
答案 0 :(得分:8)
什么是静态方法?适用于类的方法,而不是特定的实例。类签名T
中的泛型参数public class SomeClass<T>
仅适用于特定实例(因此non-static type T
)。例如SomeClass<String>
[T = String]
。<T>
。
将public static <T>SomeClass<T> newInstance(Class<T> clazz)
包含在T
的方法签名中。你这么说;对于此方法,存在泛型类型参数T
。此T
与类签名中的C
分开。所以它可能是public static <C> SomeClass<C> newInstance(Class<C> clazz)
,即<T>
。或者完全不同的东西。
但是如果你没有在方法中包含T
,编译器会认为你正在尝试在类签名中使用if (@{$edges{$location}}[0])
。这是非法的。
答案 1 :(得分:0)
在我看来,这个问题非常有趣,它解决了几个不同的问题,值得不止一个答案,尽管那个答案可能是完全正确的。
<块引用>为什么我需要在 SomeClass 前面 [Otherwise] 会有一个......错误......无法对非静态类型进行静态引用 T
静态成员、方法和字段的使用,在泛型类has certain restrictions中,参见“不能声明类型为类型参数的静态字段”一节。尽管本节讨论的是字段而不是方法,但也可以将推理扩展到方法。事实上,如果我们同意声明
private static T foo = null;
没有意义,因为编译器无法创建实例独立变量 foo
,因为泛型类可以用任何类型参数化(请记住,Java 泛型不是 C++ 模板,并且由于类型擦除前者在运行时只有一个(每个类加载器)泛型类的实例),那么为什么会像
public static T get() {
return null;
}
应该更有意义吗?
其次,当您在 T
和 SomeClass
方法中声明泛型类型 newInstance
时,实际上您隐藏第一个 T
与第二个,并且两者互不相关。对于非静态类型,类型隐藏更为明显。在示例中
class Foo<T> {
<T> T get(){ // a warning "The type parameter T is hiding the type T"
return null;
}
}
第二个 T
,在方法中声明,隐藏第一个,为类声明,这就是您收到警告 The type parameter T is hiding the type T
的地方。要消除警告,您必须将方法中的 T
替换为另一个类型变量,例如Z
,因此两者之间的区别变得明显。
class Foo<T> {
<Z> Z get(){ // no warning, T and Z are different type variables
return null;
}
}
在静态方法的情况下,编译器不会发出警告(可能是因为它认为对于静态事物是隐藏的?),但在这种情况下也存在类型隐藏。在您带来的示例中,您成功地欺骗了 Java 通用机器(恭喜 :)),但是如果我们想象以下场景(我稍微重构了您示例的语义,比如说,更传统的)
static class Factory <T extends Number> {
private T t;
public static <T> T getInstance(){
return null;
}
public T get(){
return t;
}
}
,这两行都会编译
Number n1 = longFactory.get();
Number n2 = Factory.getInstance();
,但是你在第二个上失去了类型安全,所以行
String s1 = longFactory.get(); // fails to compile with "Type mismatch: cannot convert from Long to String" error message
失败,这很好,但是行
String s2 = longFactory.getInstance(); // compiles only with a warning "static method should be accessed in a static way"
如果您错过了类型参数隐藏的重点,这不是很好,也不是您所期望的。
(在幕后,T longFactory.get()
type-erases 到 Number longFactory.get()
,而 static <T> T getInstance()
type-erases 到 {{1 }},例如
static Object getInstance()
但 Type Erasure 是另一回事)