对象的静态分派和动态分派
重写属于动态分派,重载属于静态分派
静态分派
public class Main {
public static class Father{
}
public static class Man extends Father{
}
public static class Woman extends Father{
}
public void say(Father father){
System.out.println("hello father");
}
public void say(Man man){
System.out.println("hello man");
}
public void say(Woman woman){
System.out.println("hello woman");
}
public static void main(String[] args) {
Main main = new Main();
main.say(new Father()); //hello father
main.say(new Man()); //hello man
main.say(new Woman());//hello woman
Father father = new Man();
main.say(father); //hello father
father = new Woman();
main.say(father);//hello father
}
}
上面是一个常规的类重载
Father father = new Man();
实例化了一个子类Man()对象,并将其给其父类的引用。java多态的体现
Father 称为变量的静态类型,Man称为变量的实际类型
- 静态类型在编译期就可知,而实际类型在运行期才能确定,编译器并不知道一个对象实际类型时什么,但能确定是方法在需要的是什么类型(编译时就确定)
- “在重载时是通过静态类型而不是实际类型作为判定依据”–《深入理解java虚拟机》这样说到
- 我理解成传参传的是静态类型,和实例化的对象(实际类型)是没关系的
Father father = new Man();
main.say(father); //hello father
main.say((Man) father ); //hello man
虽然编译器能确定方法的重载版本,但很多时候,重载的版本不是唯一的,则选取最合适的版本
如下代码,字符c依次向下匹配
- char - int - long -double向右转换
- 当都不存在,char自动装箱成Character
- serializable是Character类实现的一个接口
- 所有的类的父类都是object
public static void say(char c){
System.out.println("char"); //char
}
public static void say(int c){
System.out.println("int"); //int
}
public static void say(long c){
System.out.println("long" +c); //long97
}
public static void say(double c){
System.out.println("double" +c) ;//double97.0
}
public static void say(Character c){
System.out.println("Character" +c);//Charactera
}
public static void say(Serializable c){
System.out.println("Serializable" +c);//Serializablea
}public static void say(Object c){
System.out.println("Object" +c);//Objecta
}
public static void main(String[] args) {
Test_1.say('a');
}
动态分派
java的重写就是动态分派
public static class Father{
public void say(){
System.out.println("hello father");
}
}
public static class Man extends Father{
public void say(){
System.out.println("hello Man");
}
}
public static class Woman extends Father{
public void say(){
System.out.println("hello woman");
}
}
public static void main(String[] args) {
Father father = new Father();
father.say(); //hello father
father = new Man();
father.say();//hello Man
father = new Woman();
father.say();//hello woman
}
重写匹配方法流程原理
- 程序执行到改行,栈顶指向了实例化对象的实际类型,记作C
- 如果C中找到与常量中信息相匹配的方法,则进行访问权限校验,如果通过,直接引用,不通过返回IllegalAccessError异常
- 否则,按照继承关系从下到上会C的父类进行第二补操作
- 如果始终未找到,抛出AbstractMethodsError异常。