子类型多态:总是后期绑定?

时间:2015-10-11 08:51:37

标签: java polymorphism late-binding static-binding

This维基百科声明:

  

由于以前不知道特定类型的多态对象   运行时(通常),执行的函数是动态绑定的。   例如,以下Java代码:

 public void foo(java.util.List<String> list) {
     list.add("bar");  
 }
     

List是一个接口,因此list必须引用它的子类型。是一个   引用LinkedList,ArrayList或其他一些子类型   名单? add引用的实际方法直到运行时才知道。

考虑这个例子:

List<String> list;

list = new LinkedList<String>();
foo(list);

list = new ArrayList<String>();
foo(list);

为什么这里引用的实际方法直到运行时才知道?编译器无法检查对象 list 分配给哪种类型的foo的每次调用?当然,只有当程序是确定性的并且不涉及随机性时(例如用户交互),这才是可能的。

引用语句中的(一般)是关于或者我的理解是错误的吗?

在特殊情况下,程序是确定性的,是使用静态绑定还是 - 在Java中 - 始终使用动态绑定,无论可能的是什么?如果是这样,为什么?

2 个答案:

答案 0 :(得分:2)

该陈述谈及一般案例。仅给出维基百科示例的代码,不可能告诉list参数的具体类型。在您的示例中,可以告诉具体类型。

允许使用Java运行时,如果它可以检测变量的具体类型,则实际上会对方法调用进行虚拟化。

如果您对该主题感兴趣:这是一篇论文link,讨论了虚拟化技术。

答案 1 :(得分:1)

在将java源码编译为java字节码期间,不会执行虚拟化。否则这将是非常脆弱的。请注意,编译的java类通常保留二进制兼容性(有一些已知的例外)。因此,如果您的foo位于单独的类中并且您只重新编译此类,那么调用foo的类应该使用新代码而无需重新编译。

然而,虚拟化可以在运行时实现,并且实际上由大多数现代JVM(包括Oracle HotSpot JVM或课程)执行。在JIT编译期间,此方法可能会完全内联:foo个调用,LinkedList.addArrayList.add方法将合并到调用方法体中。

所以一般来说维基百科的引用是正确的:add引用的实际方法直到运行时才知道。但是,这并不意味着调用仍然是多态的,因为JVM运行时非常复杂,包括解释器,JIT编译和JIT编译代码的执行。