Java中泛型方法的类型参数在类型声明中的确切含义是什么?
我理解泛型类的类型参数,比如下面的BoxA类,<T, S>是两个不同类型的占位符,初始化时需要传入两种不同的数据类型:
class BoxA<T, S> { private T t; private S s; public void add(T t, S s) { this.t = t; this.s = s; } public T getFirst() { return t; } public S getSecond() { return s; } }
但我搞不懂泛型方法的类型参数,它和泛型类的表现不一样。比如这段代码:
class Util { public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) { return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue()); } } class Pair<K, V> { private K key; private V value; public Pair(K key, V value) { this.key = key; this.value = value; } public void setKey(K key) { this.key = key; } public void setValue(V value) { this.value = value; } public K getKey() { return key; } public V getValue() { return value; } }
我不明白这段代码为什么能运行:如果泛型方法的类型参数和泛型类一样是占位符,那compare方法应该接收不同类型的参数才对,但它实际接收两个Pair<K, V>类型的参数。我想明确public static <K, V> boolean compare()里的K和V到底是什么角色:
- 它们是方法参数的单个类型占位符?
- 还是作为方法参数的对象的类型参数的占位符?
- 或是泛型方法需要为所有访问的变量设置唯一类型参数?
核心解释:泛型方法的类型参数是约束方法内所有相关类型的统一占位符
直接给你把compare方法里的<K, V>角色说透:
它是整个方法范围内的类型契约:当你调用
compare方法时,编译器会根据传入的Pair实例的实际类型,确定K和V的具体类型,然后强制方法里所有相关类型都遵循这个契约。比如你传入两个Pair<String, Integer>,那方法里的K就是String,V就是Integer,两个参数必须是同一种Pair类型,这样才能保证getKey()和getValue()的类型匹配,调用equals()不会出问题。不是要求参数类型不同,而是要求参数类型符合占位符的统一约束:
泛型类的T、S是让类能容纳不同类型的成员,但泛型方法的<K, V>是为了让方法能处理同一种泛型参数组合的对象。compare方法的作用是比较两个Pair是否相等,那自然要求这两个Pair的key和value类型都一致——不然拿String的key和Integer的key比,逻辑上也不合理。具体到角色:它是方法参数的对象的类型参数的统一占位符:
你可以把<K, V>理解为给Pair的类型参数“定规矩”——告诉编译器:这个方法只接受两个类型参数完全相同的Pair实例,K是它们共同的key类型,V是共同的value类型。这样方法里调用p1.getKey().equals(p2.getKey())时,两个key的类型肯定一致,不会出现类型不兼容的问题。
举个调用的例子就清楚了:
// 合法:两个Pair的类型参数都是<String, Integer> Pair<String, Integer> p1 = new Pair<>("a", 1); Pair<String, Integer> p2 = new Pair<>("a", 1); Util.compare(p1, p2); // 非法:两个Pair的类型参数不匹配,编译器直接报错 Pair<String, Integer> p3 = new Pair<>("a", 1); Pair<Integer, String> p4 = new Pair<>(1, "a"); Util.compare(p3, p4);
简单总结:泛型方法的类型参数是用来统一约束方法中所有用到的泛型类型的,它不是要求参数类型不同,而是要求相关的泛型对象都遵循同一个类型参数组合,保证方法内部操作的类型安全。
内容的提问来源于stack exchange,提问作者rasputin

