如果方法定义为:
<T> List<T> transform(List<T> list)
第一个 T 增加了什么?因为它本质上与:
List<T> transform(List<T> list)
区别在于T
的范围。它可以在类级别或为每个单独的方法定义。
List<T> transform(List<T> list)
这个返回并接受List<T>
其中所有方法的T
都相同。
<T> List<T> transform(List<T> list)
此方法有自己的T
与其类的泛型类型(如果有)无关。
<T>
是定义。在使用泛型类型参数之前,需要定义泛型类型参数,就像在使用泛型类型参数之前必须定义变量一样。
请记住,T
只是一个命名约定。该标识符可以是任何内容。可能是<F>
或<Foo>
.
假设他们按照您的建议实现了它,并且编译器只是将任何缺少的类型推断为泛型类型参数。假设我有一个自定义类Foo
我忘记导入它。
List<Foo> transform(List<Foo> list)
编译器会说"好吧,我不知道Foo是什么,所以让我们假设它是一个通用参数"。然后,您的方法可以很好地编译,而您更希望编译器已捕获该错误。
或者,也许您认为T
应该是一个特例。然后,您将采用目前只是约定的东西,并将其作为语言的特殊部分。您必须处理有人创建名为T
的真实类的可能性。
因此,明确的声明有其用途,即使它们有时看起来很冗长。
<T> List<T> transform(List<T> list)
因为它本质上与:
List<T> transform(List<T> list)
不是。
在第二种情况下,必须在包含类上定义T
:
class GenericClass<T> {
List<T> transform(List<T> list) { ... }
}
然后,您只能传入/获取与类相同的元素类型的列表:
GenericClass<String> genericClass = new GenericClass<>();
List<String> stringList = genericClass.transform(Arrays.asList("")); // OK.
List<Integer> intList = genericClass.transform(Arrays.asList(0)); // Error!
但是,对于第一种形式,T
不是在类上定义的,因此每次调用时它可能不同:
class NonGenericClass {
<T> List<T> transform(List<T> list) { ... }
}
NonGenericClass nonGenericClass = new NonGenericClass();
List<String> stringList = nonGenericClass.transform(Arrays.asList("")); // OK.
List<Integer> intList = nonGenericClass.transform(Arrays.asList(0)); // OK.
这根本不一样。
<T>
声明变量,其余的是变量的使用。这直接编译失败:
public class Example {
public List<T> transform(List<T> foo) {}
}
试试吧。
如果这是您拥有的:
public class Example<T> {
public <T> List<T> transform(List<T> foo) {}
}
然后你有 2 个不相关的类型变量,不幸的是都命名为T
,这非常令人困惑;我强烈建议你不要这样做(类定义了 a,然后方法定义了自己的 T,确保该方法声明中 T 的所有用法都被假定为在方法上定义;类定义的不再可访问;它已被"阴影化"。从这个意义上说,它等同于:
public class Example {
int x;
public void foo(int x) { }
}
foo 的int x
与int x;
字段完全无关,但由于它们具有相同的名称,因此您无法引用名为x
的字段。至少为此有一个转义(this.x
仍然指字段) - 泛型没有这样的奢侈,所以,不要像这样阴影变量。
如果你有这段代码,你根本不需要在方法上有一个 var 类型;但如果你真的这样做,不要使用 T,而是使用其他任何东西:
public class Foo<T> {
public <Y> List<Y> transform(List<Y> foo) {}
}
如前所述,以下内容基本相同。
<T> List<T> transform(List<T> list)
List<T> transform(List<T> list)
但前者也允许人们进一步约束T。 例如,你可以做
<T extends Foo> List<T> transform(List<T> list) {
...
}
如果 T 子类 Foo,则只能传递List<T>
。