我正在查看JDK类的源代码。
以下方法签名让我困惑:
public static <T extends Comparable<? super T>> void sort(List<T> list);
由于该方法没有返回任何形式的所有形式类型参数?
如果方法的签名只是这样,方法的行为会如何变化:
public static void sort(List<T> list);
答案 0 :(得分:5)
如果是
public static void sort(List<T> list);
Java不知道应该从参数中推断出T
类型。它会寻找一个名为T
的具体类或接口,找不到它,并向您吐出编译器错误。
答案 1 :(得分:3)
语法:
public static void sort(List<T> list);
不合法,因为T
尚未声明。具有正确语法的最接近的代码是:
public static void sort(List<?> list);
这意味着该方法将接受任何类型的List,但是要排序列表,必须有一些方法来比较它的元素 - 因此原始签名:
public static <T extends Comparable<? super T>> void sort(List<T> list);
这意味着可以通过compareTo()
方法将每个元素与其他所有元素进行比较。
语法:
void sort(List<? extends Comparable> list)
几乎没有那么有用 - 它只要求列表包含可比较的对象,但不一定是彼此。例如,list可以包含一个String和一个Integer,它们都是Comparable,但彼此不能 - 你无法对这样的列表进行有意义的排序。这是因为每个元素的未知类型可能不同。但是,通过键入方法,类型仍然可以是任何类型,但它是列表中所有元素的相同类型。
答案 2 :(得分:1)
Sierra&amp; Bates SCJP:
泛型方法最奇怪的是你必须在方法的返回类型之前声明类型变量。
正如其他人所说,唯一的方法是
public static void sort(List<T> list);
工作是否实际上有一个名为T的类,在这种情况下,参数就像变量的任何其他类型声明一样。
也可以考虑一下来自Sierra&amp; amp;贝茨。它显示正式类型参数是为了避免命名冲突:
class X { public <X> X(X x) {} }
是的,这有效......类名,类型参数占位符和变量标识符之间没有命名冲突。
然后我们还有其他案例:
void sort(List<? extends Comparable> list)
此案例称为capture of a wildcard。编译器从通配符获取类型规范并创建匿名类型。效果与显式类型规范相同,只是该类型不能在方法实现中使用。您可以将其想象为以下伪代码:
<T_?001> void sort_?001(List<T_?001> list)
本案例展示了形式参数的另一个目标 - 它们允许在方法实现中使用命名类型。
<T extends Comparable> void sort(List<T> list) {
Iterator<T> it = list.iterator();
}
答案 3 :(得分:0)
此处类型参数仅用于将输入列表限制为仅实现Comparable
接口的元素。感谢通用参数,如果传递List
个非可比元素,则会出现编译时错误。
答案 4 :(得分:0)
type参数与方法的行为无关,它与方法的签名有关。该方法仅接受可比较的列表。如果你输入一个不可比较的列表,那么sort
就会失败 - 这是有意义的,因为如果无法比较这些元素,你想如何对它们进行排序?