之前的文章我们介绍了一下 Java 中的引用型数组类型,接下来我们再来看一下 Java 中的继承。
继承的概念
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
在日常生活中,我们会养些猫和狗,从程序的角度讲猫和狗都属于对象,那么我们就可以根据其特性来定义,如下:
1 class Dog extends Animal { 2 String name; 3 String color; 4 int age; 5 6 void run() { 7 System.out.println("我可以跑"); 8 } 9 10 void lookDoor() { 11 System.out.println("我可以看门"); 12 } 13 } 14 15 class Cat { 16 String name; 17 String color; 18 int age; 19 20 void run() { 21 System.out.println("我可以跑"); 22 } 23 24 void catchMouse() { 25 System.out.println("我可以抓老鼠"); 26 } 27 }
我们在定义 Dog 和 Cat 类的时候发现它们绝大部分属性和方法是相同的。那这样的话我们再定义其他动物的时候同样会出现这种气矿,这就造成了大量代码的重复,造成程序臃肿,不易维护。
我们可以这样解决上面的问题,将 Dog 和 Cat 类里相同的属性和方法写到一个父类里,自己特有的方法在自己的类里完成,这样就可以有效的解决上面的问题,其实这就是 Java 类的继承,如下:
1 public class HelloWorld { 2 public static void main(String[] args) { 3 Dog dog = new Dog(); 4 dog.run(); // 我可以跑 5 dog.lookDoor(); // 我可以看门 6 7 Cat cat = new Cat(); 8 cat.run(); // 我可以跑 9 cat.catchMouse(); // 我可以抓老鼠 10 } 11 } 12 13 class Animal{ 14 String name; 15 String color; 16 int age; 17 18 void run() { 19 System.out.println("我可以跑"); 20 } 21 } 22 23 class Dog extends Animal { 24 void lookDoor() { 25 System.out.println("我可以看门"); 26 } 27 } 28 29 class Cat extends Animal { 30 void catchMouse() { 31 System.out.println("我可以抓老鼠"); 32 } 33 }
在上面的代码中,我们定义类一个 Animal 类,里面定义了 Dog 和 Cat 类中相同的属性和方法,然后我们在定义 Dog 和 Cat 类的时候通过 extends Animal 的方式来继承 Animal 类,当我们继承 Animal 类的时候,Animal 类中的属性和方法就会被一并继承过来,这样我们在声明 Dog 和 Cat 类的时候便可以调用从 Animal 类及成果来的属性和方法,这就是继承。
继承:
1、目的:避免代码重复,有利于代码的重用
2、通过 extends 实现继承
3、父类:所有子类所用共有的属性和方法;子类:子类所特有的属性和方法
4、子类继承父类后,子类具有 子类+父类 的属性和方法
5、一个父类可以有多个子类,一个子类只能有一个父类-----单一继承
6、继承具有传递性
7、Java 规定:构造子类之前必须先构造父类,子类构造中若没有调用父类的构造,则默认super(),若自己调了,则不再默认提供。
在上面的5,6条我们可以看出,在写程序时,我们不能这样 class Dog extends Cat extends Animal 的形式来实现继承,这样会出现编译错误,但是我们可以通过 class Cat extends Animal class Dog extends Cat 的形式来逐层进行继承。
在上面的代码中我们已经了解了 Java 的继承,接下来我们在结合之前说到的构造方法来介绍一下 super
1 public class HelloWorld { 2 public static void main(String[] args) { 3 Dog dog = new Dog(); 4 dog.run(); // 我可以跑 5 dog.lookDoor(); // 我可以看门 6 dog.name = "旺财"; 7 dog.color = "黄色"; 8 dog.age = 8; 9 System.out.println("我叫" + dog.name + ",今年" + dog.age + ",是" + dog.color + "的"); // 我叫旺财,今年8,是黄色的 10 11 Cat cat = new Cat("咪咪", "白色", 5); 12 cat.run(); // 我可以跑 13 cat.catchMouse(); // 我可以抓老鼠 14 System.out.println("我叫" + cat.name + ",今年" + cat.age + ",是" + cat.color + "的"); // 我叫咪咪,今年5,是白色的 15 } 16 } 17 18 class Animal { 19 String name; 20 String color; 21 int age; 22 23 Animal() { 24 25 } 26 27 Animal(String name, String color, int age) { 28 this.name = name; 29 this.color = color; 30 this.age = age; 31 } 32 33 void run() { 34 System.out.println("我可以跑"); 35 } 36 } 37 38 class Dog extends Animal { 39 Dog() { 40 super(); 41 } 42 43 void lookDoor() { 44 System.out.println("我可以看门"); 45 } 46 } 47 48 class Cat extends Animal { 49 Cat(String name, String color, int age) { 50 super(name, color, age); 51 } 52 53 void catchMouse() { 54 System.out.println("我可以抓老鼠"); 55 } 56 }
在上面的代码中,我们在父类 Animal 类中分别定义了一个无参构造和一个有参构造,在子类 Dog 中定义了一个无参构造,在子类 Cat 中定义类一个有参构造,我们发现,在子类的构造方法中我们添加了一个 super() 的方法,通过这种方法我们就可以继承来自父类的构造方法,从而在实例化我们的子类的时候初始化我们想要的参数,在继承父类的有参构造的时候需要将父类有参构造的参数传递进来。
接下来我们来看下面的代码:
1 public class HelloWorld { 2 public static void main(String[] args) { 3 Dog dog1 = new Dog(); 4 Dog dog2 = new Animal(); // 编译错误 5 Animal animal1 = new Animal(); 6 animal1.run(); // 我可以跑 7 animal1.lookDoor(); // 编译错误 8 Animal animal2 = new Dog(); 9 animal2.run(); // 我可以跑 10 animal1.lookDoor(); // 编译错误 11 } 12 } 13 14 class Animal { 15 String name; 16 String color; 17 int age; 18 19 Animal() { 20 21 } 22 23 Animal(String name, String color, int age) { 24 this.name = name; 25 this.color = color; 26 this.age = age; 27 } 28 29 void run() { 30 System.out.println("我可以跑"); 31 } 32 } 33 34 class Dog extends Animal { 35 Dog() { 36 super(); 37 } 38 39 void lookDoor() { 40 System.out.println("我可以看门"); 41 } 42 }
在上面的代码中,我们如果通过 new Dog() 来创建一个 Dog 对象是完全没有问题的,通过 new Animal() 来创建一个 Animal 对象也是没有问题的,但是通过 new Animal() 来创建一个 Dog 对象会编译错误,通过 new Dog() 来创建一个 Animal 对象也是没有问题的,我们可以这样理解,new 类名() 所指向的类必须是本类或父类,不能是子类,即等号左侧的类型必须大于或等于等号右侧的 new 出来的类。当大于时我们称之为向上造型。向上造型后 子类 将不再具备其自己定义的方法,只有父类的方法。