Java学习笔记之深入理解动态绑定和静态绑定
来源:互联网 发布:cs编程里包括什么 编辑:程序博客网 时间:2024/05/31 19:05
基本概念
动态绑定和静态绑定是Java中两个重要的概念。首先思考这么一个问题,当一个类中存在方法名相同但参数不同(重载)的函数或同一类层次结构下同一名称的方法(重写),程序在执行的时候该如何辨别区分呢?这里就需要用到Java中的动态绑定和静态绑定来解决。那么什么是动态绑定和静态绑定呢?
- 绑定:指一个方法的调用与方法所在的类关联起来
- 静态绑定:方法在程序编译期进行绑定
- 动态绑定:方法在程序运行时根据具体对象的类型进行绑定
静态绑定 VS 动态绑定
- 静态绑定发生在编译期(Compile time),而动态绑定发生在运行时(Runtime)
private
,final
andstatic
方法和变量使用静态绑定,而虚函数(virtual methods)则会根据运行时的具体对象进行绑定- 静态绑定使用的是类信息,而动态绑定使用的是对象信息
- 重载方法(overloaded methods)使用的是静态绑定,而重写方法(overridden methods)使用的是动态绑定
虚函数:在Java语言中, 所有的方法默认都是”虚函数”。只有以关键字 final 标记的方法才是非虚函数。虚函数是面向对象编程实现多态的基本手段。
静态绑定示例
例1:
class A { public void hello(String str) { System.out.println("a String instance in A"); } public void hello(Object str) { System.out.println("a Object instance in A"); }}public class BindingDemo { public static void main(String args[]) { String str = ""; Object obj = ""; A a = new A(); a.hello(str); a.hello(obj); }}
输出结果:
a String instance in Aa Object instance in A
分析:可以看出,在A中有两个同名但参数不同的方法(重载),在调用方法a.hello()时,程序会自动根据输入的参数类型来选择具体调用哪个方法,其后的原理就是静态绑定,即在编译期根据参数类型进行静态绑定。
动态绑定实例
例2:
class A { public void hello() { System.out.println("hello in A"); }}class B extends A { @Override public void hello() { System.out.println("hello in B"); }}public class StaticBindingDemo { public static void main(String args[]) { A a = new B(); a.hello(); }}
输出结果:
hello in B
分析:B继承于A,并重写了A中的方法hello(),从结果可知,a.hello()调用的不是A中的hello(),而是B中的hello(),这正是因为程序在运行时发生了动态绑定。同时也说明了重写方法使用的是动态绑定。
相关问题探讨
Stack Overflow上探讨了这么一个问题,具体如下:
class A { int x = 5;} class B extends A { int x = 6;} class SubCovariantTest extends CovariantTest { public B getObject() { System.out.println("sub getobj"); return new B(); }}public class CovariantTest { public A getObject() { System.out.println("ct getobj"); return new A(); } public static void main(String[]args) { CovariantTest c1 = new SubCovariantTest(); System.out.println(c1.getObject().x); }}
输出结果:
sub getobj5
看到这样的输出结果,很多人可能会很纳闷,从第一个输出结果sub getobj
可以看出调用的是B对象,但从x输出值上看,却是A对象,这是怎么一回事?!先不急着解决这个问题,我们先来看下下面这段程序:
class A { int x = 5; public void doSomething() { System.out.println("A.doSomething()"); }} class B extends A { int x = 6; public void doSomething() { System.out.println("B.doSomething()"); }} public class Main { public static void main(String args[]) { A a=new B(); System.out.println(a.x); a.doSomething(); }}
输出结果:
5B.doSomething()
分析:根据前面讲解的静态绑定和动态绑定知识,我们可以清楚的知道,在调用方法a.doSomething()时发生的是动态绑定,故输出结果是B.doSomething(),但当调用a.x时,又发生了些什么呢?!这里,我们需要了解一个概念:在Java中,变量(fields)没有多态这个说法,只有方法(methods)有。即变量不存在动态绑定,它是在编译期进行绑定。在编译期,变量x和方法doSomething()都是和A类进行绑定的,而在程序运行时,doSomething()方法会根据运行的对象类型进行动态绑定,即绑定B类,从而执行的是B类中的doSomething()方法。而x变量不进行动态绑定,所以执行的还是A类中的x变量。再回到最开始的那个问题:在编译期,c1绑定的是类CovariantTest,则c1.getObject()返回的是类A,故c1.getObject().x指的是A.x;在运行时,c1.getObject()则会根据运行的对象进行动态绑定,即绑定类SubCovariantTest,而c1.getObject().x不会在进行动态绑定,所以x的值还是类A中的x的值。
有人可能对变量x到底是属于哪个类还是很疑惑,那么我们再通过一个例子来进行说明:虽然类A和类B都有一个变量x,但是它们并不是同一个x,既然这样,我们就可以用不同的名称表示这两个变量,将类B中的变量x改为y,具体如下
class A { int x = 5;}class B extends A { int y = 6;}class SubCovariantTest extends CovariantTest { public B getObject() { System.out.println("sub getobj"); return new B(); }}public class CovariantTest { public A getObject() { System.out.println("ct getobj"); return new A(); } public static void main(String[] args) throws java.lang.Exception { CovariantTest c1 = new SubCovariantTest(); System.out.println(c1.getObject().y); }}
在编译期,如果c1.getObject()返回的是类B,那么上面程序完全没问题,但实际上,会出现以下编译错误。说明,在编译期,c1.getObject()返回的是类A,c1.getObject().x指的是A.x,而且在运行期间不会发生改变。
上面的问题解决了,可能有人还会继续问,那么怎样才能达到变量被重写的效果?我们可以这样实现
class A { int x = 5; public int getX() { return x; } public void doSomething() { System.out.println("A.doSomething()"); }}class B extends A { int x = 6; public int getX() { return x; } public void doSomething() { System.out.println("B.doSomething()"); }}public class Main { public static void main(String args[]) { A a = new B(); System.out.println(a.getX()); a.doSomething(); }}
输出结果:
6B.doSomething()
显然,正是利用方法的动态绑定达到变量被重写的效果。
参考资料
- Java中的静态绑定和动态绑定
- Java中的静态绑定和动态绑定
- What is Static and Dynamic binding in Java with Example
- Java学习笔记之深入理解动态绑定和静态绑定
- 理解java静态绑定和动态绑定
- 学习笔记之 java的动态绑定与静态绑定
- 深入理解C++的动态绑定和静态绑定
- 深入理解C++的动态绑定和静态绑定转
- 深入理解C++的动态绑定和静态绑定
- 深入理解C++的动态绑定和静态绑定
- 深入理解C++的动态绑定和静态绑定
- 深入理解C++的动态绑定和静态绑定
- 深入理解C++的动态绑定和静态绑定
- 深入理解C++的动态绑定和静态绑定
- 深入理解C++的动态绑定和静态绑定
- 深入理解C++的动态绑定和静态绑定
- 深入理解C++的动态绑定和静态绑定
- 深入理解C++的动态绑定和静态绑定
- 深入理解C++的动态绑定和静态绑定
- 深入理解C++的动态绑定和静态绑定
- 深入理解C++的动态绑定和静态绑定
- 新的起点!!!新的目标!!!
- Android 使用Socket实现服务器与手机客户端的长连接一:一对一聊天
- mad_libs_function_in_R
- 浅析JSP Model1与Model2区别
- leetcode 91 Decode Ways
- Java学习笔记之深入理解动态绑定和静态绑定
- Leetcode-integer-to-roman
- sphinx 源码阅读之数据结构与算法
- 二分搜索
- 安卓手机屏幕同步工具asm.jar
- mongodb工具类
- noi2010能量采集(在网格点中互质的特点)
- 微信sdk的用法
- Data and Times