深究继承示例(多态,继承,构造函数)
关于继承,为什么一直说在含有构造函数的继承中,父类中一定要有不含参数的构造函数才可以。
首先说明默认值的一个知识点:在定义全局变量的时候,即使不给变量赋值,变量也是有值的,比如整形变量的默认值是0
package day07; public class Trys { private static int p ; public static void main(String[] args) { System.out.println(p); } }
0
*但是局部变量就必须赋值,不赋值是没法输出的。
其次说明一个多态的知识点:
像Father father = new Son(); 这样的吧,这有一种专业说法,叫“父类引用指向子类对象”。 首先 new Son();是肯定动态创建了一个子类对象的 。 Father father 则是一个创建了一个父类引用对象。 Father father = new Son(); 就是将父类引用指向子类对象,这是java里很常用的用法。 这时候如果用father调用方法father.method() ,如果method()方法只有父类有,子类里没有写,那么就调用父类里那个方法体。如果在子类里有对method()进行了重写(注意是重写不是重载), 那么就调用子类里的那个方法体。
java多态之Override
Override(重写)是子类与父类的一种多态性体现。
Override允许子类改变父类的一些行为。
为什么需要Override:当父类不满足子类的一些要求时我们就需要子类对父类的一些行为进行重写。
例如:某公司里的员工的电话号码不允许对外公开,而销售人员(员工)的电话号码则需要对外公开。
这时我们就可以这样做:
- public class Employee {
- private String mobile;
- public Employee(String mobile) {
- this.mobile = mobile;
- }
- protected String showMess(){
- return "电话号码:"+mobile;
- }
- }
员工类的showMess方法是protected的,所以位于其他包的对象是访问不到的。
然后定义一个销售人员的类(Sales),并继承Employee类
- public class Sales extends Employee{
- //子类除了具有父类的一些属性,也可以有自己的一些属性
- private String msn;
- public Sales(String mobile,String msn) {
- super(mobile);
- this.msn = msn;
- }
- @Override
- public String showMess() {
- return super.showMess()+"==msn:"+this.msn;
- }
- }
注意这时被覆盖的showMess方法的访问级别是public,可以被任何其他对象访问到。
关于Override有几点要注意的地方:
1.被覆盖方法的访问控制级别可以不一样。
例如上例父类的showMess方法的访问级别为protected的,而子类覆盖的showMess方法访问级别则为public的。
但子类的访问级别必须要高于父类被覆盖方法的访问级别,如果父类是public的而子类是protected的则是错误的。
2.方法被定义为private或static或final的则不能被覆盖。
3.方法的返回类型:子类的返回类型可以是更具体的对象,例如可以将Employee类的返回类型改为Object也正确。而倒过来则错误。
4.在方法调用时先会在子类中找覆盖的方法,如果子类中没有则会在父类中去找。
- public class Parent {
- private int num(int i,int j){
- return i+j;
- }
- public static void main(String[] args) {
- Parent p = new Child();
- System.out.println(p.num(1, 2));
- }
- }
- class Child extends Parent{
- public int num(int x,int y){
- return x-y;
- }
- }
这段代码的执行结果为什么呢?如果你回答-1则错了,正确答案是3。
为什么呢?因为父类的num方法是private的,所以不能被覆盖,所以子类的num方法不是一种Override,因此在子类找不到被覆盖的num方法就会执行父类的num方法。所以结果输出为3.
- public class Parent {
- public int test(){
- //执行子类的num方法
- return num(1,2);
- }
- protected int num(int i,int j){
- return i+j;
- }
- public static void main(String[] args) {
- Parent p = new Child();
- System.out.println(p.test());
- }
- }
- class Child extends Parent{
- public int num(int x,int y){
- return x-y;
- }
- }
那么这段代码的执行结果是-1,因为父类test方法调用的是子类的num方法。
多态和继承(Inheritance)
严格来说,多态与继承、重载并不是孤立的,他们之间存在着紧密的联系,多态是建立在这两者的基础之上的(实际上继承就有用重载这一特性)。
传统的多态实际上就是由虚函数(Virtual Function)利用虚表(Virtual Table)实现的(早期C模拟OO特性时使用最多,C++的实现也是,后来的技术未作研究,是否使用VT不得而知),自然是离不开继承,换句话说多态实际上覆盖了继承。
正是由于继承与多态的紧密联系,使得我们很容易张冠李戴,那么如何区别呢?
举个常用的例子:
package day2; public abstract class Duotai_1 { public boolean isSharp(){ return true; } public abstract int getSides(); public static void main(String[] args) { Triangle tri = new Triangle(); System.out.println("Triangle is a type of sharp? " + tri.isSharp()); Duotai_1 sharp = new Rectangle(); System.out.println("My sharp has " + sharp.getSides() + " sides."); } } class Triangle extends Duotai_1 { public int getSides() { return 3; } } class Rectangle extends Duotai_1 { public int getSides() { return 4; } }
Triangle is a type of sharp? true
My sharp has 4 sides.
那么这种类的关系叫做继承,下面这种使用方式也是继承所带来的:
Triangel tri = new Triangle();
println("Triangle is a type of sharp? " + tri.isSharp());
而这种方式则是多态:
Sharp sharp = new Rectangle();
println("My sharp has " + sharp.getSides() + " sides.");
这两者区别在哪?很显然,继承是子类使用父类的方法,而多态则是父类使用子类的方法。
其技术上的区别是绑定时期,晚期绑定一定是多态。
当创建的子类对象需要访问到父类构造函数的时候,如果父类中没有显写的构造函数,那么会访问父类中默认的空构造,如果有构造函数,那么空构造失效,如果显写的构造函数不含参数,那么当子类需要访问到父类构造函数的时候不需要用到super关键字,但是如果父类中的构造函数含有参数的话,子类中需要访问到父类的构造函数的话需要在函数的首行写super(参数)举个例子(注意私有变量只能在本类中有效)
package day07; class SuperClass { private int number; public SuperClass() { this.number = 0; System.out.println(this.number+" "+number+" "+"1111111111111111111"); } public SuperClass(int number) { this.number = number; System.out.println(this.number+" "+number+" "+"22222222222222222222"); } public int getNumber() { System.out.println(this.number+" "+number+" "+"0000000000000000000"); number++; System.out.println(this.number+" "+number+" "+"0000000000000000000"); return number; } } class SubClass1 extends SuperClass { public SubClass1(int number) { // super(number); } } class SubClass2 extends SuperClass { private int number; public SubClass2(int number) { // super(number); System.out.println("77777777777777777"+" "+number); } } public class Extends1 extends SuperClass { private int number;//有默认值,默认值为0 public Extends1(int number) { // super(number); System.out.println("44444444444444"+" "+number); } public int getNumber() { System.out.println(this.number+" "+number+" "+"55555555555555555555"); number++; System.out.println(this.number+" "+number+" "+"55555555555555555555"); return number; } public static void main(String[] args) { SuperClass ss = new SuperClass(20); System.out.println(ss.getNumber()); System.out.println("\n\n"); SuperClass s = new Extends1(20); System.out.println(s.getNumber()); System.out.println("\n\n"); SuperClass s1 = new SubClass1(20); System.out.println(s1.getNumber()); System.out.println("\n\n"); SuperClass s2 = new SubClass2(20); System.out.println(s2.getNumber()); //结论一:多态时,当子类覆盖了父类的方法,使用子类覆盖的方法 //结论二:当子类覆盖父类的成员变量时,父类方法使用的是父类的成员变量,子类方法使用的是子类的成员变量 } }
20 20 22222222222222222222
20 20 0000000000000000000
21 21 0000000000000000000
21
0 0 1111111111111111111
44444444444444 20
0 0 55555555555555555555
1 1 55555555555555555555
1
0 0 1111111111111111111
0 0 0000000000000000000
1 1 0000000000000000000
1
0 0 1111111111111111111
77777777777777777 20
0 0 0000000000000000000
1 1 0000000000000000000
1
再比如:
package day07; class SuperClass { private int number; // public SuperClass() { // this.number = 0; // System.out.println(this.number+" "+number+" "+"1111111111111111111"); // } public SuperClass(int number) { this.number = number; System.out.println(this.number+" "+number+" "+"22222222222222222222"); } public int getNumber() { System.out.println(this.number+" "+number+" "+"0000000000000000000"); number++; System.out.println(this.number+" "+number+" "+"0000000000000000000"); return number; } } class SubClass1 extends SuperClass { public SubClass1(int number) { super(number); } } class SubClass2 extends SuperClass { private int number; public SubClass2(int number) { super(number); System.out.println("77777777777777777"+" "+number); } } public class Extends1 extends SuperClass { private int number;//有默认值,默认值为0 public Extends1(int number) { super(number); System.out.println("44444444444444"+" "+number); } public int getNumber() { System.out.println(this.number+" "+number+" "+"55555555555555555555"); number++; System.out.println(this.number+" "+number+" "+"55555555555555555555"); return number; } public static void main(String[] args) { SuperClass ss = new SuperClass(20); System.out.println(ss.getNumber()); System.out.println("\n\n"); SuperClass s = new Extends1(20); System.out.println(s.getNumber()); System.out.println("\n\n"); SuperClass s1 = new SubClass1(20); System.out.println(s1.getNumber()); System.out.println("\n\n"); SuperClass s2 = new SubClass2(20); System.out.println(s2.getNumber()); //结论一:多态时,当子类覆盖了父类的方法,使用子类覆盖的方法 //结论二:当子类覆盖父类的成员变量时,父类方法使用的是父类的成员变量,子类方法使用的是子类的成员变量 } }
20 20 22222222222222222222
20 20 0000000000000000000
21 21 0000000000000000000
21
20 20 22222222222222222222
44444444444444 20
0 0 55555555555555555555
1 1 55555555555555555555
1
20 20 22222222222222222222
20 20 0000000000000000000
21 21 0000000000000000000
21
20 20 22222222222222222222
77777777777777777 20
20 20 0000000000000000000
21 21 0000000000000000000
21
再比如:
package day07; class SuperClass { private int number; public SuperClass() { this.number = 0; System.out.println(this.number+" "+number+" "+"1111111111111111111"); } public SuperClass(int number) { this.number = number; System.out.println(this.number+" "+number+" "+"22222222222222222222"); } public int getNumber() { System.out.println(this.number+" "+number+" "+"0000000000000000000"); number++; System.out.println(this.number+" "+number+" "+"0000000000000000000"); return number; } } class SubClass1 extends SuperClass { public SubClass1(int number) { super(number); } } class SubClass2 extends SuperClass { private int number; public SubClass2(int number) { super(number); System.out.println("77777777777777777"+" "+number); } } public class Extends1 extends SuperClass { private int number;//有默认值,默认值为0 public Extends1(int number) { super(number); System.out.println("44444444444444"+" "+number); } public int getNumber() { System.out.println(this.number+" "+number+" "+"55555555555555555555"); number++; System.out.println(this.number+" "+number+" "+"55555555555555555555"); return number; } public static void main(String[] args) { SuperClass ss = new SuperClass(20); System.out.println(ss.getNumber()); System.out.println("\n\n"); SuperClass s = new Extends1(20); System.out.println(s.getNumber()); System.out.println("\n\n"); SuperClass s1 = new SubClass1(20); System.out.println(s1.getNumber()); System.out.println("\n\n"); SuperClass s2 = new SubClass2(20); System.out.println(s2.getNumber()); //结论一:多态时,当子类覆盖了父类的方法,使用子类覆盖的方法 //结论二:当子类覆盖父类的成员变量时,父类方法使用的是父类的成员变量,子类方法使用的是子类的成员变量 } }
20 20 22222222222222222222
20 20 0000000000000000000
21 21 0000000000000000000
21
20 20 22222222222222222222
44444444444444 20
0 0 55555555555555555555
1 1 55555555555555555555
1
20 20 22222222222222222222
20 20 0000000000000000000
21 21 0000000000000000000
21
20 20 22222222222222222222
77777777777777777 20
20 20 0000000000000000000
21 21 0000000000000000000
21