ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

面向对象基本特征:多态

2019-02-09 23:41:41  阅读:256  来源: 互联网

标签:void print Father 多态 Son 面向对象 基本特征 方法 public


多态是面向对象最重要的特征。具体到Java中是如何体现的呢。

多态在我们的使用中其实就是重载与重写。下面分别进行讲述一下。

重载

重载的定义:一个类中,如果有两个方法的方法名相同,但参数列表不同,可以说一个方法是另一个方法的重载。

注意2点:1.方法名相同   2.参数列表不同(参数列表为:参数的类型,参数的个数)

调用重载方法的时候,JVM会根据不同的参数列表来选择合适的方法。

我们来看一下代码:

public class Main {
    public static void main(String[] args) {
        Father f= new Father();
        f.print();
        f.print(5);
    }
}
class Father{public void print() {
        System.out.println("father");
    }public void print(int x) {
        System.out.println(x);
    }
}

看一下字节码:

可以很明显看到invokevirtual调用了不同的方法。

重写

当子类拥有和父类相同的方法(方法名,参数列表相同),则说子类重写了父类的方法。

注:1.方法名相同  2.参数列表相同  3  子类重写方法的访问修饰符必须大于等于父类的方法。(比如父类为 protected void print(){},则子类必须protected或者public)

来看一下重写的例子:

public class Main {
    public static void main(String[] args) {
        Father son = new Son();
        son.print();
    }
}
class Father{public void print() {
        System.out.println("father");
    }
}
class Son extends Father{public void print() {
        System.out.println("son");
    }
}

结果很明显:son

看一下字节码:

从第9行可以看到:invokevirtual指令的注释显示了是Father.print()的符号引用。但是为什么结果是son而不是father呢。

首先要说关于静态类型和实际类型:

Father son = new Son(); 中

Father称为静态类型,而Son称为实际类型。区别在于静态类型在编译期就会确定,而实际类型要在运行期才能确定。编译器编译程序时候并不知道对象的实际类型是什么。

所以由于重载在编译期就确定了类型。所以这个过程也可以叫静态分派。而重写是动态分派。

来看一下invokevirtual指令的解析过程(参考《深入理解Java虚拟机》):

1.找到操作数栈顶的第一个元素所指向的对象的实际类型。记作C(在上面代码实际类型为Son)

 2.如果在类型C中找到与常量中描述符合简单名称都相符的方法,则进行访问权限校验,如果通过则返回这个方法的直接引用。查找过程结束。不通过的话则返回java.lang.IllegalAccessError异常

(上面代码指的就是查找print()方法,在Son中找到了。所以就成功结束查找过程)

3.否则,按照继承关系从下往上一次对C的各个父类进行第2步的搜索和验证过程。

4.如果始终没有找到合适的方法,则抛出java.lang.AbstractMethodError异常。

由于invokevirtual指令执行的第一步就是在运行期确定实际类型。所以invokevirtual指令把常量池的方法的类方法符号引用(即print())解析到了Son的直接引用中。所以我们具体看到的结果就是Son.print()。

这就是重写的本质。

 

关于Father f  = new Son() 中 f的方法问题。

在题目中经常会看到关于下面的题目:

public class Main {
    public static void main(String[] args) {
        Father son = new Son();
        son.print();
    }
}
class Father{
public void print() { System.out.println("father"); } } class Son extends Father{
public void printSon() { System.out.println("son"); } }

结果大家都能记住:father

这里就可以用invokevirtual指令的解析顺序来解释:C还是Son类,但是Son中并没有print()方法,所以往父类找。在父类找到了返回print()方法的直接引用。所以最后调用的是Father.print()。

注:以前看视频这个是父类引用指向子类的实例对象。向上转型之类的,列举一堆例子概念让人记住结果而已。反正我现在已经不怎么记得了。

当从invokevirtual指令解析顺序去理解,其实整个过程会变得清晰多了。

标签:void,print,Father,多态,Son,面向对象,基本特征,方法,public
来源: https://www.cnblogs.com/fabaogege/p/10358507.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有