天天看点

基于Java代码对this,动态绑定,覆盖和隐藏的探讨和思考

先放一段代码,通过修改参数来理解以下四个问题:

1.父类子类混合创建一个新对象的构造逻辑(多态性及动态绑定)

2.this.方法实质

3.静态方法的隐藏(成员变量)

4.非静态方法的覆盖

对1的解释:声明父类新建子类对象的与常规新建对象的区别(A p = new B()):

先看如下代码,A是B的父类,m()被覆盖。

class A {
    int x=;//被隐藏
    A() {
        System.out.println("这里构建了一个父类对象");
    }

    void m() {//被覆盖
        System.out.println("这里是父类的实例方法m()");
    }

    void m1() {
        this.m();
        this.m2();
        this.m3();
        System.out.println(this.x);
        System.out.println("这里是父类的实例方法m1()");
    }

    static void m2(){//被隐藏
    System.out.println("这里是父类的静态方法m2()");
}

    void m3() {//未被覆盖
        System.out.println("这里是父类的实例方法m3()");
    }   
}

class B extends A {
    int x=;
    B() {
        System.out.println("这里构建了一个子类对象");
    }

    void m() {
        System.out.println("这里是子类的实例方法m()");
    }

    static void m2(){
    System.out.println("这里是父类的静态方法m2()");
}

}

public class Test1 {
    public static void main(String[] args) {
        A a = new A();
        a.m1();
        System.out.println();
        B b = new B();
        b.m1();
        System.out.println();
        A c = new B();
        c.m1();
    }
}
           

输出结果为:

这里构建了一个父类对象

这里是父类的实例方法m()

这里是父类的静态方法m2()

这里是父类的实例方法m3()

1

这里是父类的实例方法m1()

这里构建了一个父类对象

这里构建了一个子类对象

这里是子类的实例方法m()

这里是父类的静态方法m2()

这里是父类的实例方法m3()

1

这里是父类的实例方法m1()

这里构建了一个父类对象

这里构建了一个子类对象

这里是子类的实例方法m()

这里是父类的静态方法m2()

这里是父类的实例方法m3()

1

这里是父类的实例方法m1()

可以看出:

构造顺序为

父类属性初始化-》父类构造方法-》子类属性初始化-》子类构造方法

而且实际会构造的对象要看声明的类型,如果是子类就是子类的。

其中

A c = new B();

构建顺序为先构建父类,再构建子类。但只能调用被子类覆盖的方法,而不能调用子类独用的方法。(在B中设计一个父类没有的m3方法,然后用c.m3()调用,发现报错,m3()未被定义。哪怕m3()改为静态方法也不行)

也就是说只多了一个被覆盖的方法,其他没影响。

而且this指的就是this这个词自己所在的类,而非网上部分文章说的是建立的对象(new后面的)的类,只是被覆盖的方法除外,隐藏了没用。而且A中的this去掉也没有影响。

父类中被覆盖的方法在父类中无法调用,在子类中可以用super调用,其他地方可以通过只建立父类对象直接调用,用子类间接调用只能找子类里用的super方法的。

被隐藏的变量和静态方法可以在父类中被直接调用,其他和覆盖一致。

下面可以利用另一端代码进行练习测试:

class A{
    int x = ;//被隐藏
    void print(){//被覆盖
        System.out.println("这里是父类方法,x="+x);//父类A的方法中访问的变量必然是A类或A的父类的,不可能访问B类的。
        m();//父类A的方法中调用的实例方法m()是子类B的,由于发生了覆盖
    }
    void m(){//被覆盖
        System.out.println("这里是父类的实例方法m()");
    }
    static void m2(){//被隐藏
        System.out.println("这里是父类的静态方法m2()");
    }
}
class B extends A{
    int x = ; 
    void print(){
        System.out.println("这里是子类方法,x="+x);//子类方法访问的变量是子类对象的(当然条件是子类中声明了这个变量)
        System.out.println("这里是子类方法,super.x="+super.x);//super.x是父类对象的
        super.print();//调用父类的print()方法
        m();//调用本对象的m()方法
    }
    void m(){
        System.out.println("这里是子类的实例方法m()");
    }
    static void m2(){
        System.out.println("这里是子类的静态方法m2()");
    }
    static void m3(){//静态与否都没用
        System.out.println("这里是子类的实例方法m3()");
    }
}
public class Test{
    public static void main(String []s){
        A p = new B();
        System.out.println(p.x);//通过引用变量p来访问变量或静态方法,要看p的声明类型。所以x是A类的。
        p.m2();//同上。静态方法m2()是A类的。
        p.print();//通过引用变量p来访问实例方法,要看p指向的对象的实际类型。由于覆盖,调用的print()方法是子类的。
        p.m3();//报错The method m3() is undefined for the type A
    }
}