是Java编译时参数调度破坏了吗?

时间:2014-07-23 18:07:48

标签: java parameters overloading dispatch method-dispatch

我已经知道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); ??

那样明确地转发它

1 个答案:

答案 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 ...它通常会解析为。