我已经知道 Java 根据编译时类型分派(dispatch)方法。然而,我有一个案例,我希望它能起作用,但事实并非如此。
考虑这个简单的例子:
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)
是最合适的? ?
因为我在编译时有一个 map ,所以一切都应该可以工作!为什么我必须明确地向下转换它,如 foo.bar((Map<String, Object>)map);
??
最佳答案
我尝试了下面的这个程序,但出现错误 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,?>
),则调用虚拟字节代码会要求提供 Map 参数。您的版本也可以工作,因为强制转换强制编译器为 Map 发出 invokevirtual,而不是 Object...它通常会解析为。
关于java - Java 编译时参数分配是否损坏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24917787/