继承可以解决代码的复用,让我们的编程更加靠近人类思维,当多个类存在相同的属性和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends语句来声明继承。
注意事项
Ⅰ.java 中支持单继承,不直接支持多继承,但对c++中的多继承机制进行改良。
Ⅱ.ava支持多层(多重)继承
Ⅲ.Java所有类都是Object类的子类
Ⅳ.JDK中有202个包3777个类、接口、异常、枚举、注释和错误
实例
1 package com.beekc.www; 2 3 public class Beekc { 4 public static void main(String[] args) { 5 Pupil stu1 = new Pupil(); 6 stu1.pay(500); 7 stu1.printName(); 8 stu1.printFee(); 9 10 MiddleStu stu2 = new MiddleStu(); 11 stu2.pay(500); 12 stu2.printName(); 13 stu2.printFee(); 14 15 ColStu stu3 = new ColStu(); 16 stu3.pay(500); 17 stu3.printName(); 18 stu3.printFee(); 19 } 20 } 21 22 //将学生的共有属性提出,做一个父类 23 class Stu 24 { 25 protected int age; 26 public String name; 27 public float fee; 28 //编程中,如果你不希望子类继承某个属性或者方法 29 //将其声明为private 30 private String job; 31 32 public void printName() 33 { 34 System.out.printf("名字:" + this.name + "\t"); 35 } 36 public void printFee() 37 { 38 System.out.println("交费" + this.fee + "¥"); 39 } 40 } 41 42 //小学生类 43 class Pupil extends Stu 44 { 45 public Pupil() 46 { 47 name = "小学生"; 48 } 49 //交费 50 public void pay(float fee) 51 { 52 this.fee = fee; 53 } 54 } 55 56 //中学生类 57 class MiddleStu extends Stu 58 { 59 public MiddleStu() 60 { 61 name = "中学生"; 62 } 63 //交费 64 public void pay(float fee) 65 { 66 this.fee = fee * 0.8f; 67 } 68 } 69 70 //大学生类 71 class ColStu extends Stu 72 { 73 public ColStu() 74 { 75 name = "大学生"; 76 } 77 //交费 78 public void pay(float fee) 79 { 80 this.fee = fee * 0.6f; 81 } 82 }
运行结果
继承的细节
1 //第一种情况:当子类与父类的变量的名称相同时,在子类里想用父类的变量时用super关键字 2 public class Father { 3 int num = 4; 4 } 5 6 public class Son extends Father { 7 int num = 5; 8 public void show() 9 { 10 System.out.println(this.num + "..." + super.num); 11 } 12 } 13 14 public class ExtendsDemo { 15 public static void main(String[] args) 16 { 17 Son son = new Son(); 18 son.show(); 19 20 } 21 }
1 //第二种情况:当父类的方法与子类的方法想同时,子类的方法会去覆盖父类的方法,这里会去输出子的内容,想要用父类的方法用super关键字 2 public class Father { 3 public void show() 4 { 5 System.out.println("Father run ..."); 6 } 7 } 8 9 public class Son extends Father { 10 public void show() 11 { 12 System.out.println("Son run ..."); 13 } 14 } 15 16 public class ExtendsDemo { 17 public static void main(String[] args) 18 { 19 new Son().show(); 20 } 21 }
1 //第三种情况:子类方法覆盖父类方法时,子类权限必须要大于等于父类的权限 2 //这个程序会报错 3 public class Father { 4 public void show() //这里权限是public 5 { 6 System.out.println("Father run ..."); 7 } 8 } 9 10 public class Son extends Father { 11 private void show()//这里权限是private 12 { 13 System.out.println("Son run ..."); 14 } 15 } 16 17 public class ExtendsDemo { 18 public static void main(String[] args) 19 { 20 new Son().show(); 21 } 22 }
class Father
{
public static void show()
{
System.out.println("run show");
}
}
class Son extends Father
{
public void show()
{
System.out.println("run show");
}
}
class ExtendsDome
{
public static void main(String[] args)
{
Son son = new Son();
son.show();
}
}
1 //第四种情况:会报错的程序:静态方法只能覆盖静态方法,或被静态覆盖 2 class Father 3 { 4 public static void show() 5 { 6 System.out.println("run show"); 7 } 8 } 9 10 class Son extends Father 11 { 12 public void show() 13 { 14 System.out.println("run show"); 15 } 16 } 17 18 class ExtendsDome 19 { 20 public static void main(String[] args) 21 { 22 Son son = new Son(); 23 son.show(); 24 } 25 }
什么时候使用覆盖操作?
当对一个类进行子类的扩展时,子类需要保留父类的功能声明。但是要定义子类中该功能的特有内容时,就使用覆盖操作完成。
子父类中的构造函数的特点
在子类构造对象时,发现,访问子类构造函数时,父类也运行。为什么呢?原因是:在子类的构造函数中第一行有一个默认的隐式语句。super();
子类的实例化过程,子类中的构造函数默认都会访问父类中的空参数构造函数.
1 class Father 2 { 3 Father() 4 { 5 System.out.println("Father run"); 6 } 7 } 8 9 class Son extends Father 10 { 11 Son() 12 { 13 //super(); //隐藏的语句,此语句是调用父类的空参数构造函数 14 System.out.println("Son run"); 15 //return; 16 } 17 } 18 19 class ExtendsDome 20 { 21 public static void main(String[] args) 22 { 23 new Son(); 24 } 25 } 26 27 //运行结果 28 //Father run 29 //Son run
为什么子类实例化的时候要访问父类的构造函数呢?
那是因为子类继承了父类,获取到了父类的内容(属性),所以在使用父亲内容之前,要先看父类如何对自己的内容进行初始化的。所以子类在构造对象时,必须访问父类中的构造函数。为什么完成这个必须的动作,就在子类的构造函数中加入了super()语句。 如果父类中没有定义空参数构造函数,那么子类的构造函数必须用super明确要掉调用父类中哪个构造函数.同时子类构造函数中如果使用this调用了本类构造函数时,那么super就没有被替换了,因为super和this只能定义在第一行,所以只能有一个。但是可以保证的是,子类中肯定会有其他的构造函数访问父类的构造函数。注意的是super语句必须要定义在子类构造函数的第一行,因为父类的初始化动作要先完成。
1 class Father 2 { 3 Father() 4 { 5 System.out.println("Father run"); 6 } 7 Father(int x) 8 { 9 System.out.println("Father run ..." + x); 10 } 11 } 12 13 class Son extends Father 14 { 15 Son() 16 { 17 //super();//这里回去初始化父类的构造函数 18 System.out.println("Son run"); 19 return; 20 } 21 Son(int x) 22 { 23 this(); 24 //super();//这里的super()会被替换,因为this()与super()只能写在第一行。 25 System.out.println("Son run ..." + x); 26 return; 27 } 28 } 29 30 class ExtendsDome 31 { 32 public static void main(Sring[] args) 33 { 34 new Son(6); 35 } 36 } 37 38 //运行结果 39 //Father run 40 //Son run 41 //Son run ...6
1 class Father 2 { 3 Father() 4 { 5 super(); 6 show(); 7 return; 8 } 9 10 public void show() 11 { 12 System.out.println("Father show"); 13 } 14 } 15 16 class Son extends Father 17 { 18 int num = 8; 19 20 Son() 21 { 22 super(); 23 //通过super初始化父类时,子类的成员变量并未显示初始化。等super()父类初始化完毕后,才进行子类的成员变量显示初始化。 24 show(); 25 return; 26 } 27 public void show() 28 { 29 System.out.println("Son show ..." + num); 30 } 31 } 32 33 class ExtendsDome 34 { 35 public static viod main(String[] args) 36 { 37 Son son = new Son(); 38 son.show(); 39 } 40 } 41 42 //运行结果 43 //Son show ...0 44 //Son show ...8