Java 中的静态绑定和动态绑定

yufei       5 年, 5 月 前       1073

静态绑定 :静态绑定又称为 早期绑定,是编译器在编译时就可以解析的绑定。 所有静态,私有和最终方法的绑定都在编译时完成。

为什么 static,final 和 private 方法的绑定始终是静态绑定 ?

静态绑定往往有着更好的性能,因为不需要额外的开销。编译器知道 static,final 和 private 方法不能被重写,且总是被本地类 ( local class ) 的对象所访问。编译器可以轻而易举的推断出类的对象 (一定属于本地类)。

这就是为什么这种方法的绑定是静态的。

有点难以理解了?

简单的说,在继承体系中,static 是类的方法,而 final 和 private 方法是不能被子类重写的。因此在编译器就知道调用这些方法的对象所指向的类是哪个。

我们写一段代码来演示下上面说的

JavaTester.java

public class JavaTester  
{
    public static class superclass 
    { 
        static void print() 
        { 
            System.out.println("print in superclass."); 
        } 
    }

    public static class subclass extends superclass 
    { 
        static void print() 
        { 
            System.out.println("print in subclass."); 
        } 
    } 

    public static void main(String[] args) 
    { 
        superclass a = new superclass(); 
        superclass b = new subclass(); 
        a.print(); 
        b.print(); 
    }
}

在看到答案之前,你能猜到上面的代码输出结果是什么吗?

编译运行上面的范例,输出结果如下

[yufei@www.twle.cn java]$ javac JavaTester.java && java JavaTester
print in superclass.
print in superclass.

结果是不是大跌眼镜,你可能会问,b.print() 为什么不是输出 print in subclass. ?

上面的代码中,我们使用 superclass 类的引用创建了一个 subclass 类的对象和一个 superclass 类的对象。

由于 superclass 类的的 print() 方法是静态的,编译器知道它不会在子类中被重写,因此编译器在编译期间知道要调用哪个打印方法。

实际上,看起来就是在子类中重写了的啊...对吧。

因此没有歧义。

如是我们把变量 b 的类型改成 subclass ,结果又会是是如何呢 ?

public class JavaTester  
{
    public static class superclass 
    { 
        static void print() 
        { 
            System.out.println("print in superclass."); 
        } 
    }

    public static class subclass extends superclass 
    { 
        static void print() 
        { 
            System.out.println("print in subclass."); 
        } 
    } 

    public static void main(String[] args) 
    { 
        superclass A = new superclass(); 
        subclass B = new subclass(); 
        A.print(); 
        B.print(); 
    }
} 

编译运行的结果如下

[yufei@www.twle.cn java]$ javac JavaTester.java && java JavaTester
print in superclass.
print in subclass.

动态绑定

动态绑定 就是编译器在编译时并不能确定要调用哪个方法。 例如重写 ( override ) 。因为重写 ( override ) ,父类和子类都存在相同的方法。

我们写一段代码演示下动态绑定

public class JavaTester  
{
    public static class superclass 
    { 
        void print() 
        { 
            System.out.println("print in superclass."); 
        } 
    }

    public static class subclass extends superclass 
    { 
        @Override
        void print() 
        { 
            System.out.println("print in subclass."); 
        } 
    } 

    public static void main(String[] args) 
    { 
        superclass A = new superclass(); 
        superclass B = new subclass(); 
        A.print(); 
        B.print(); 
    }
}

编译运行以上代码,输出结果如下

[yufei@www.twle.cn java]$ javac JavaTester.java && java JavaTester
print in superclass.
print in subclass.

结果怎么不一样了 ?

不要着急,我们一步一步来解析上面这小段代码

  1. print() 方法是一个普通的方法,没有 staticfinalprivate 修饰。而且在子类中还重写了 print() 方法。

  2. 当调用 b.print() 方法时,编译器并不能确定调用的是哪个 print() 方法 (虽然我们开发者一眼能看出是调用哪个,但编译器没有我们这么聪明),因为编译器只通过引用变量而不是对象类型,因此绑定将延迟到运行时,因此将根据对象上的类型调用相应的 print() 版本。

静态绑定和动态绑定的知识点

  • privatefinalstatic 成员(方法和变量)使用静态绑定,而对于虚方法( Java 方法默认都是虚方法)绑定在运行时基于运行时对象完成。

  • 静态绑定使用类型信息进行绑定,而动态绑定使用对象来解析绑定

  • 重载 ( overload ) 方法使用静态绑定(在有多个具有相同名称的方法时调用哪个方法),而重写 ( override ) 方使用动态绑定,即运行时确定。

后记

关于动态绑定和静态绑定,其实就一句话: 能根据变量类型确定的方法属于静态绑定,只能根据对象确定的方法则是动态绑定

目前尚无回复
简单教程 = 简单教程,简单编程
简单教程 是一个关于技术和学习的地方
现在注册
已注册用户请 登入
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.