Java 动态绑定

本文详细解析了Java中的overload(静态多态)和override(动态绑定)概念,通过实例演示了编译类型与运行类型的区别,并展示了如何通过四步查找机制调用方法。理解了这些,有助于掌握面向对象编程中的多态原理。
摘要由CSDN通过智能技术生成

首先复习两个概念

  • Overload:
    • 也叫静态多态(static dynamic) 是通过同名方法定义不同(参数类型、个数、顺序)来实现的,因此在调用时就可以知道具体执行的哪个方法(根据调用时传的参数就好~),所以发生在编译期,这个过程叫做静态绑定
    • 用 private/static/final参数修饰的方法一定是静态绑定的
  • Override:
    • 通过子类重写父类方法+父类引用可以指向子类对象实现,因此调用的是父类or子类的方法要通过具体调用时的引用类型来确定
      再引入两个概念:编译类型和运行类型
  • 编译类型:就是变量在定义时的类型,在写代码的时候就确定了,所以说是编译类型,比如Son son,那么son就是Son类型的引用
  • 运行类型:变量真正指向的类型,因为父类引用可以指向子类对象,所以父类引用的运行类型可能并不是父类

这里看一个栗子:

public class Test {

  public boolean equals( Test other ) {
    System.out.println( "Inside of Test.equals" );
    return false;
  }

  public static void main( String [] args ) {
    Object t1 = new Test();
    Object t2 = new Test();
    Test t3 = new Test();
    Object o1 = new Object();

    int count = 0;
    System.out.println( count++ );// prints 0
    t1.equals( t2 ) ;
    System.out.println( count++ );// prints 1
    t1.equals( t3 );
    System.out.println( count++ );// prints 2
    t3.equals( o1 );
    System.out.println( count++ );// prints 3
    t3.equals(t3);
    System.out.println( count++ );// prints 4
    t3.equals(t2);
  }
}

只会显示出一句话~ 在3后面
因为Test中的equals方法并没有Override Object类中的equals方法(参数类型不同,Object类中的equals方法参数为Object),所以只有t3.equals(t3)符合Test类中定义的equals方法,因此只会输出一句话,这是在编译期间就确定的

补充一个小芝士:
记得在python中写类的方法时需要显示传入一个this参数,代表该类本身,其实java中在类里定义方法时也会传入this对象,只不过是隐式的。
那么假设现在有一个类,内部有一个方法,参数是一个引用,那么在具体调用时编译器会按照以下类型来寻找
this.func(this) // 查看自己有木有一毛一样的方法
super.func(this) // 查看父类有木有一毛一样的方法
this.func(super) // 把this对象转为super,再查看自己有木有一毛一样的方法
super.func(super) // 把this对象转为super,再查看父类有木有一毛一样的方法

为了充分理解,来一个栗子二:

class Super {
    public void methodC(Super arg) {
        System.out.println("C1");
    }
    public void methodC(Sub arg) {
        System.out.println("C2");
    }
}

class Sub extends Super {
    public void methodC(Super arg) {
        System.out.println("C3");
    }
    public void methodC(Sub arg) {
        System.out.println("C4");
    }
}

public class Main {
    public static void main(String[] args) {
        Super one = new Sub();
        Super two = new Sub();
        Sub three = new Sub();
        one.methodC(two);
        one.methodC(three);
    }
}

因为我们知道实例方法执行时因为有动态绑定机制,所以在运行时执行的是Sub类的方法(因为one指针所指的是Sub对象),因此第一次调用匹配的是Sub类中的第一个方法,第二次调用匹配的是Sub类中的第二个方法。注意,通过引用调用方法时会有多态性,先看该引用的运行类型,如果引用是作为参数出现的,那么先看他的编译类型,也就是说参数匹配时首先考虑的还是编译类型~
下面再通过一个栗子理解一下上面说的调用方法的四部曲~

  • this.func(this)
class Super {
    public void methodC(Super arg) {
        System.out.println("C1");
    }
    public void methodC(Sub arg) {
        System.out.println("C2");
    }
}

class Sub extends Super {
    public void methodC(Super arg) {
        System.out.println("C3");
    }
    public void methodC(Sub arg) {
        System.out.println("C4");
    }
}

public class Main {
    public static void main(String[] args) {
        Sub  one = new Sub();
        Sub two = new Sub();
        one.methodC(two);// C4
    }
}
  • super.func(this)
class Super {
    public void methodC(Super arg) {
        System.out.println("C1");
    }
    public void methodC(Sub arg) {
        System.out.println("C2");
    }
}

class Sub extends Super {
    public void methodC(Super arg) {
        System.out.println("C3");
    }
}

public class Main {
    public static void main(String[] args) {
        Sub  one = new Sub();
        Sub two = new Sub();
        one.methodC(two); // C2
    }
}
  • this.func(super)
class Super {
    public void methodC(Super arg) {
        System.out.println("C1");
    }
}

class Sub extends Super {
    public void methodC(Super arg) {
        System.out.println("C3");
    }
}

public class Main {
    public static void main(String[] args) {
        Sub  one = new Sub();
        Sub two = new Sub();
        one.methodC(two);	// C3
    }
}
  • super.func(super)
class Super {
    public void methodC(Super arg) {
        System.out.println("C1");
    }
}

class Sub extends Super {

}

public class Main {
    public static void main(String[] args) {
        Sub  one = new Sub();
        Sub two = new Sub();
        one.methodC(two);// C1
    }
}

参考资料:
java-dynamic-binding-and-method-overriding
static-vs-dynamic-binding-in-java
java-dynamic-binding-confusion

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值