我已经知道Java会根据编译时类型调度方法。但是我有一个案例,我希望它可以工作,但事实并非如此。
考虑这个简单的例子:
class Foo{
void bar(Object... objects) { //do something }
void bar(Map<String, Object> map) { //do something else }
}
和调用代码:
Foo foo = new Foo();
HashMap<String, T> map = createSomeHashMap(); //wil generate HashMap
foo.bar(map);
为什么Java认为最适合调用bar(Object... objects)
?
由于我在compileTime上有一个Map,所以应该可以工作!为什么我必须像foo.bar((Map<String, Object>)map);
??
答案 0 :(得分:2)
我在下面尝试了这个程序并得到了一个错误Type mismatch: T cannot be converted to Object
:
public class DispatchTest
{
private void bar( HashMap<String, Object> map )
{
}
public static void main( String[] args )
{
test();
}
private static <T> void test()
{
DispatchTest dt = new DispatchTest();
HashMap<String,T> map = new HashMap<>();
dt.bar( map );
}
}
所以我猜这是弄乱你的泛型。将参数类型从Object
更改为?
,这对我有用。
private void bar( HashMap<String, ?> map )
{
}
编辑:为了详细说明这一点,我将代码放回到原始代码中,并添加了一个类似示例bar(Object...)
的方法。这是生成的Java字节代码:
private static <T extends java/lang/Object> void test();
Code:
0: new #3 // class quicktest/DispatchTest
3: dup
4: invokespecial #4 // Method "<init>":()V
7: astore_0
8: new #5 // class java/util/HashMap
11: dup
12: invokespecial #6 // Method java/util/HashMap."<init>":()V
15: astore_1
16: aload_0
17: iconst_1
18: anewarray #7 // class java/lang/Object
21: dup
22: iconst_0
23: aload_1
24: aastore
25: invokevirtual #8 // Method bar:([Ljava/lang/Object;)V
28: return
在这种情况下,您可以看到已经确定Map
参数不合适,第25行的invokevirtual字节代码需要Object...
版本的调用。这是在编译时完成的,而不是运行时。
如果我将代码更改回我的建议(使用Map<String,?>
),则invokevirual字节代码会询问Map参数。您的版本也可以工作,因为强制转换会强制编译器为Map发出invokevirtual而不是Object ...它通常会解析为。