Java 多态之“绑定”
来源:互联网 发布:企业网络公关 编辑:程序博客网 时间:2024/06/03 18:56
写在前面:
在刚开始学习JavaSE 时,学习多态时对下面几段程序输出的结果感觉到很诧异:
public class Sub extends Super{ public int num = 1; public int getNum(){ return num; } public static void main(String[] args) { Super sup = new Sub(); System.out.println("sup.num = "+sup.num); //调用父类的属性 System.out.println("sup.getNum() = "+sup.getNum()); //调用子类的方法 }}class Super{ public int num = 0; public int getNum(){ return num; }}
输出:
sup.num = 0
sup.getNum() = 1
当将方法定义为静态时输出又会是什么样的呢?
public class Sub extends Super{ public static int num = 1; public static int getNum(){ return num; } public static void main(String[] args) { Super sup = new Sub(); System.out.println("sup.num = "+sup.num); //调用父类的属性 System.out.println("sup.getNum() = "+sup.getNum()); //调用父类的方法 }}class Super{ public static int num = 0; public static int getNum(){ return num; }}
输出:
sup.num = 0
sup.getNum() = 0
如果将方法定义成私有的又会是什么结果呢?
public class Sub extends Super{ private void f(){ System.out.println("Sub f run........... "); }}class Super{ private void f(){ System.out.println("Super f run........... "); } public static void main(String[] args) { Super sup = new Sub(); sup.f(); //调用父类的方法 }}
输出:
Super f run………..
为什么会出现这样的输出结果呢?
在当时刚开始学Java 时,当时的疑惑主要有:
①为什么第一个程序在向上转型的过程中调用的是父类的字段,以及子类的方法
②为什么第二个程序在向上转型的过程中调用的是父类的字段,以及父类的方法
后来在网上搜了一下知道了“绑定”这个概念,但是也只是很浅显的知道了有这个概念,最近在看《Java 编程思想》对“绑定”这个概念有了更深刻的认识,现在分享出来供大家参考:
绑定:将一个方法调用同一个方法主题关联起来被称为绑定。
静态绑定:若程序执行前绑定(如果有的话,由编译器和链接程序实现),叫做前期绑定。
后期绑定:在运行时根据对象的类型进行绑定。后期绑定也叫做动态绑定或运行时绑定。
在Java 中除了static 方法和final 方法(private 方法属于final 方法)之外,其他的方法都属于后期绑定。为什么要将一个方声明为final 的呢?因为这样做可以有效“关闭”动态绑定,或者说告诉编译器不需要对其进行动态绑定。
Java 中所有的方法都是通过动态绑定实现多态。因此子类在向上转型时调用的是子类的方法(此方法时非静态的),这就可以解释为什么在第一段程序中调用getNum() 方法输出的是子类的方法。
只有普通的方法调用是多态的,因此如果你要访问某个作用域或静态方法,这个访问将在编译器进行解析。正如第一个程序中输出的是父类的成员,以及第二个程序中将方法修饰成static 时输出的就是父类的成员和父类的方法了(失去了多态的特性)。静态方法是与类,而并非与单个对象相关联的。如果你并不想将方法定义成静态的还想要得到Super.num,必须显示的指明super.num,就像下面这样:
public class Sub extends Super{ public int num = 1; public int getNum(){ return super.num; } public static void main(String[] args) { Super sup = new Sub(); System.out.println("sup.getNum() = "+sup.getNum()); }}class Super{ public int num = 0; public int getNum(){ return num; }}
输出:
sup.getNum() = 0
对于第三段程序将方法定义成private 的,我们期望是输出的是子类的方法运行,但是结果却出我们所料,这是动态绑定的缺陷所造成的结果,以及包括上面的域与静态方法都是它的缺陷造成的(也就是说这两种缺陷是前期绑定)。
结论就是:
只有非private 方法才可以被覆盖,但是还是要注意覆盖private 方法的现象,这时编译器虽然不会报错,但是它不会按照我们期望的那样执行。确切的说,在导出类中,对于基类中的private 方法最好不要采取一样的名字。在这里再强调一下这句话:在Java 中除了static 方法和final 方法(private 方法属于final 方法)之外,其他的方法都属于后期绑定。
其实在实践过程中,这种混淆的问题通常不会发生,因为你通常会将所有的域都设成private 的,因此不能直接访问它们,其副作用是只能通过方法获取它们。另外,你几乎不可能将基类中的域和导出类的域赋予相同的名字。
参考资料《Java 编程思想》Bruce Eckel 著 陈昊鹏 译
- Java 多态之“绑定”
- Java 多态之“绑定”
- Java之动态绑定
- java 多态与绑定
- Java之动态绑定/多态/迟绑定
- Java的多态(静态绑定和动态绑定)
- Java进阶之动态绑定
- C++多态之动态绑定
- java动态绑定和多态
- java多态与动态绑定例子
- Java中的方法绑定及多态
- Java多态与动态绑定
- Java 中的多态和动态绑定
- java多态和动态绑定
- Java中的多态和动态绑定
- java初始化顺序,多态以及绑定
- Java中的多态和动态绑定
- Java多态和动态绑定
- OBS屏幕录制软件
- Java对象的创建过程
- Nginx的一些基本功能
- C++学习笔记--类的静态成员变量和静态成员函数
- Java对象的访问定位
- Java 多态之“绑定”
- 公众获取用户地理位置-php开发微信公众号
- jdbc连接Oracle示例
- 单机安装spark
- I2C接口
- 零基础学seo教程并非易事
- 再谈Docker容器单机网络:利用iptables trace和ebtables log
- 对通过函数申请内存的理解
- 关于Java工程的资源目录