鉴于以下不是非常有用的代码:
package com.something;
import java.util.ArrayList;
import java.util.Collection;
//Not a generic class!
public class Test {
public <T> void plain(T param1, T param2) {}
public <T> void fancy(T param1, Collection<T> param2) {}
public void testMethod() {
//No error
fancy("", new ArrayList<String>());
//Compiler error here!
fancy("", new ArrayList<Integer>());
//No error
plain("", new ArrayList<Integer>());
}
}
(请纠正我的理解,如果它错了!)
第二次调用fancy()
是一个编译器错误,因为Java无法推断两个参数之间的任何常见类型(不能推断Object
,因为第二个参数必须是Collection
。)
对plain()
的调用是而不是编译器错误,因为Java在两个参数之间推断出Object
的公共类型。
我最近遇到的代码的方法签名类似于plain()
。
我的问题是:
plain()
的签名对任何内容都有用吗?
也许编写该代码的人认为plain()
的签名会强制两个参数在编译时具有相同的类型,显然不是这种情况。
使用plain()
这样的签名编写方法有什么不同或有益,而不是仅仅将这两个参数定义为Object
?
答案 0 :(得分:4)
虽然编译器不会推断出一个人可能想要的泛型类型,但它将强制执行明确指定的类型约束。以下调用会导致类型错误。
this.<String>plain("", new ArrayList<Integer>()); /* Compiler error. */
参数化方法&lt; String&gt;类型为Test的String(String,String)不适用于参数(String,ArrayList&lt; Integer&gt;)
答案 1 :(得分:3)
我猜你可以说它可以作为某种文档,因此用户知道你希望两个参数属于同一类型。当然,任何两个对象在某种程度上属于同一类型(它们都是Object
),所以这是一个毫无意义的陈述。
长话短说,这是一个无用的签名。
当然,如果plain
返回了T
类型,那就是另一个故事。
答案 2 :(得分:1)
对fancy()的第二次调用是编译器错误,因为Java无法推断 两个参数之间的任何常见类型(不能从而推断出Object 第二个参数必须是Collection。)
好吧,我不确定这是什么原因,我会说原因是T
中的泛型类型Collection<T>
是一个不变量,其值决定了第一个参数{{1}的类型}}
例如,这是有效的:
T
因为所有fancy("", new ArrayList<CharSequence>()); //compiles Ok
都是String
。从CharSequences
推断出类型后,预计第一个参数为CharSequence
。
但是,这是无效的:
ArraysList<CharSequence>
因为预期第一个参数的类型为fancy((CharSequence)"", new ArrayList<String>()); //compiler error
,我们无法确保所有String
实际上都是CharSequences
类型,对吗?
因此,AFAIK,类型不兼容的原因是由于这种情况下泛型的性质,而不是第二种类型是String
的事实。