方法调用绑定:
将一个方法调用和方法主体关联起来叫做绑定。即:编译器遇到了一个方法调用,就会把程序陷入进与之绑定的方法主体内。
绑定分为前期绑定和后期绑定。
前期绑定:
在程序运行前绑定,即编译连接过程中。我的理解是:Java不会去找是哪个对象进行了这次方法调用(因为这时根本就没有对象),而是在引用所在的类中找到相应方法并绑定。以下代码同理,Father类型的引用f不能调用Son类中新增的方法cry(),因为Father类中找不到cry()方法。
这种绑定在面向过程的语言中很常见。在Java中,只有static方法和final方法是前期绑定。BTW,构造函数是隐式的static方法,private是隐式的final方法。
public class Son extends Father{
Wife w=new Wife();
public Son(){
System.out.println("Son");
}
void cry(){
System.out.println("...");
}
public static void main(String args[]){
Father f=new Son();
//can't compile f.cry();
}
}
后期绑定/动态绑定/运行时绑定:
与前期绑定相反,此时程序运行,已经为对象分配了内存空间,Java可以去找到对应对象,进而找到其拥有的方法。找到相应方法后再执行绑定,这也是实现多态的前提。
Java中除了static方法和final方法,其他所有方法都是后期绑定。
多态:
某个方法接收一个基类对象作为参数,由于子类型能向上转型为基类型,因此该方法可以接收各种不同子类的对象作为参数,通过后期绑定以实现同一个方法,多种不同表现的效果。这就是多态。具体见以下代码,同一个方法,接收不同类型的对象,表现出不同的效果。
class Shape{
public void draw(){}
}
class Circle extends Shape{
public void draw(){
System.out.println("Circle");
}
}
class Square extends Shape{
public void draw(){
System.out.println("Square");
}
}
public class Driver {
public static void main(String args[]){
drawShape(new Circle());
drawShape(new Square());
}
static void drawShape(Shape s){
s.draw();
}
}
另外,多态只对方法有作用,对变量无效。可以理解为:Java中的所有变量都是前期“绑定”的。
构造器的调用顺序:
1. 在其他任何事物发生前,将分配给对象的存储空间初始化为二进制的零。
2. 调用基类构造器(若此时基类构造器中访问了其他变量,则会显示变量值为0;若此时基类构造器中所调用的方法被子类覆盖,则将会调用子类中的方法)
3. 初始化成员变量
4. 调用自己的构造器
可以理解为:每个导出类对象中都包含了一个基类对象,对象的生成过程由里向外,且每个对象构造时都是先初始化成员变量,再调用自己的构造函数。
public class Son extends Father{
public Son(){
System.out.println("Son");
}
public void age(){
System.out.println("Son's age");
}
public static void main(String args[]){
new Son();
}
}
class Father{
public Father(){
age();
System.out.println("Father");
}
public void age(){
System.out.println("Father's age");
}
}
以上代码输出依次为:Son's age、Father、Son