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中 - 始终使用动态绑定,无论可能的是什么?如果是这样,为什么?
答案 0 :(得分:2)
该陈述谈及一般案例。仅给出维基百科示例的代码,不可能告诉list
参数的具体类型。在您的示例中,可以告诉具体类型。
允许使用Java运行时,如果它可以检测变量的具体类型,则实际上会对方法调用进行虚拟化。
如果您对该主题感兴趣:这是一篇论文link,讨论了虚拟化技术。
答案 1 :(得分:1)
在将java源码编译为java字节码期间,不会执行虚拟化。否则这将是非常脆弱的。请注意,编译的java类通常保留二进制兼容性(有一些已知的例外)。因此,如果您的foo
位于单独的类中并且您只重新编译此类,那么调用foo
的类应该使用新代码而无需重新编译。
然而,虚拟化可以在运行时实现,并且实际上由大多数现代JVM(包括Oracle HotSpot JVM或课程)执行。在JIT编译期间,此方法可能会完全内联:foo
个调用,LinkedList.add
和ArrayList.add
方法将合并到调用方法体中。
所以一般来说维基百科的引用是正确的:add
引用的实际方法直到运行时才知道。但是,这并不意味着调用仍然是多态的,因为JVM运行时非常复杂,包括解释器,JIT编译和JIT编译代码的执行。