Java继承与多态一瞥

Java是一种OOP的语言,在OOP语言的基本特性中,继承(Inheritance)与多态(Polymorphism)经常是面试官考察 的核心,在很多同学的面试过程中,往往被问到的都是他们的基本感念,这也是很容易回答的。但是作为程序 员,我们需要深入的了解这些关系而不仅仅是停留在字面上的理解。包子今天向广大的Java爱好者讲解一下继 承(Inheritance)与多态(Polymorphism)关系在Java中的表现方式。

程序分析

public class TestClass {
    int a;
    int b;
    public TestClass() {
        a = 5;
        b = 6;
        print();
    }
 
    public void print() {
        System.out.println(this.getClass() + ": a:" + this.a + ", b:" + this.b);
    }
 
    public static void main(String[] args) {
        TestClass test1 = new TestClass();
        TestClass test2 = new TestClass2();
    }
 
    class TestClass2 extends TestClass {
        public TestClass2() {
            super();
            a = 1;
            b = 2;
            print();
        }
 
        public void print() {
            System.out.println(this.getClass() + ": a:" + this.a + ", b:" + this.b);
        }
    }
}

上面这段程序很简单, 我们首先定义的一个基本类叫做TestClass,在TestClass中有两个int的变量,分别是a,b. 并 且在TestClass里面还有一个print()的函数去将当前的Class跟a,b打印出来。 然后我们在TestClass的构造函数中 分别对a,b 赋值。并且调用print()函数。 接下来,我们定义了另外一个类叫做TestClass2, 这个TestClass2是extends TestClass,在TestClass2中我们 override了函数print() 。然后TestClass2的构造函数中,我们首先调用了父类的构造函数super(),然后我们对 a,b重新赋值,并且调用函数print().

下面是这段程序的运行结果:

class TestClass: a:5, b:6

class TestClass2: a:5, b:6

class TestClass2: a:1, b:2

细心的同学可能已经发现在运行结果中,class TestClass2 出现了两次,或许有人会问,为什么在TestClass2在调 用super()的时候,明明是调用TestClass中的print但是我们的结果却是class TestClass2. 这是因为当我们创建这个 类的时候我们已经声明了当前这个子类的类型是TestClass2, 因此无论调用父类的任何function, this.getClass()永远 在runtime的时候指向当前的子类。 所以我们得到的结果是TestClass2.

程序分析

public class TestClass {
    int a;
    int b;
    public TestClass() {
        a = 5;
        b = 6;
        print();
    }
 
    public void print() {
        System.out.println(this.getClass() + ": a:" + this.a + ", b:" + this.b);
    }
 
    public static void main(String[] args) {
        TestClass test1 = new TestClass();
        TestClass test2 = new TestClass2();
        TestClass test3 = new TestClass3();
    }
}
 
class TestClass2 extends TestClass {
    public TestClass2() {
        super();
        a = 1;
        b = 2;
        print();
    }
}
 
class TestClass3 extends TestClass2 {
    public TestClass3() {
        print();
    }
}

我们又定义了一个新的类TestClass3, 这个TestClass3是extends TestClass2的。

在TestClass3的构造函数中只调用:

class TestClass: a:5, b:6

class TestClass2: a:5, b:6

class TestClass2: a:1, b:2

class TestClass3: a:5, b:6

class TestClass3: a:1, b:2

class TestClass3: a:1, b:2

看到上面显示的运行结果是不是很多人都会感觉到吃惊,因为觉得在TestClass3中,我们并没有调用任何super() 之类的function, 为什么TestClass3的结果是这样的:

class TestClass3: a:5, b:6

class TestClass3: a:1, b:2

class TestClass3: a:1, b:2

这是因为在Java instantiate 一个sub class的时候,super class的constructor 同样也会执行。即使我们在sub class的constructor中没有明确的指出super(),但是java的编译器会将super()自动地放在sub class constructor 里面 的第一个statement执行。这就是为什么我们会看到TestClass3自动的调用了super().

程序分析

public class TestClass {
    int a;
    int b;
    public TestClass() {
        print();
    }
 
    public void print() {
        System.out.println(this.getClass() + ": a:" + this.a + ", b:" + this.b);
    }
 
    public static void main(String[] args) {
        TestClass test1 = new TestClass();
        TestClass test2 = new TestClass2();
        TestClass test3 = new TestClass3();
    }
}
 
class TestClass2 extends TestClass {
    public TestClass2() {
        super();
        a = 1;
        b = 2;
        print();
    }
}
 
class TestClass3 extends TestClass2 {
 
    public TestClass3() {
        print();
    }
 
}

在这里,我们在TestClass的constructor里面取消了对a,b的赋值。 然后print()函数还是要将当前的a,b至打印出:

class TestClass: a:0, b:0

class TestClass2: a:0, b:0

class TestClass2: a:1, b:2

class TestClass3: a:0, b:0

class TestClass3: a:1, b:2

class TestClass3: a:1, b:2

到这里,可能很多不是学java的人会感到很奇怪,为什么对一个以没有initialization的变量,我们依旧能print出 来结果。这其实是考察到了Java本身的一种性质, 因为在Java里面,所有的东西都是一个类(Class), 而在这些类 的最高层,我们可以看成是Java的root,存在着一种特殊的类叫做Object. 而TestClass其实也是一种Object。在 Java里面,int 变量的初始值就会在Object里面被赋值成0. 所以即使我们看上去是没有赋值的变量(a&b), 它们本 身其实还有有初始值的,那就是0。

上面就是包子为大家总结的Java编程过程中的继承与多态的关系。

博客推送