大家好,今天这期我们学习java面向对象的四大核心特征中的继承,其实这期很简单的,一个国家的文化文明就是不断延续和发展的。延续和发展其实就是继承一部分。
下面我们举个例子:

上边图片我们可以看出,小猫小狗都属于动物,他们都延续动物的大类下,动物大类包含了很多的动物,为了方便大家理解,举了常见的小动物例子,小猫,小狗他们有名字并且他们有吃饭,睡觉的行为,那么根据关系我们创建3个类。
Animal:name,eat(),paly(),sleep()
Cat:name,eat(),paly(),sleep()
Dog:name,eat(),paly(),sleep()
这是动物类:
` public class Animal {
csharp
private String name;
public void eat(){
System.out.println(name+"吃饭");
}
public void play(){
System.out.println(name+"玩耍");
}
public void sleep(){
System.out.println(name+"睡觉");
}
}`
这是小猫类:
`public class Cat { private String name;
csharp
public void eat(){
System.out.println(name+"吃饭");
}
public void play(){
System.out.println(name+"玩耍");
}
public void sleep(){
System.out.println(name+"睡觉");
}
}`
这是小狗类:
`public class Dog { private String name;
csharp
public void eat(){
System.out.println(name+"吃饭");
}
public void play(){
System.out.println(name+"玩耍");
}
public void sleep(){
System.out.println(name+"睡觉");
}
}`
观察三个类我们能得到什么结论呢?我们发现Animal包含Cat和Dog中所有的名字(属性)和行为(方法),那么我们在Cat和Dog中写的现有的属性和方法是不是有些冗余呢?答案是的,那这时候我们将Cat和Dog去继承Animal所有的属性和方法,就可以避免写出冗余代码,提高了代码的复用性,那么我们就知道了,Cat和Dog是Animal的子类,Animal是就是他们的父类,那么,继承的目的就是子类对父类发展和延续,延续的是父类现有的所有属性和方法,发展的是子类可以自己创建新的属性和方法。
继承的关键字为:extends,继承后我们改写一下代码段,看一下效果:
`public class Cat extends Animal{ private String sex; public void getSex(){ System.out.println("性别:" + sex); }
}
public class Dog extends Animal{ private int age; public void getAge(){ System.out.println("年龄:" + age); } }`
我们看到了Cat和Dog继承后的代码发现是不是Cat多了性别,Dog多了年龄,这么写是不是看上去简洁多了,而且子类在父类基础上新增了属性和方法。
其实前边我埋了一个坑,如果耐心读到这里的读者应该知道了,Cat和Dog是不能继承到Animal中private修饰的属性和方法的,如果想继承到Animal的所有方法,可以扩大访问权限,比如上期我们学习的protected、public修饰符,可以让子类访问父类的所有属性和方法。
在java中有一个祖先类,所有类都默认继承它,它是始祖,文明起始于它,它是Object类,关系如下:

我们深入理解一下继承关系,继承是可以实现单继承、多层继承、同类继承,但是不可以实现多对一的情况(比如一个子类继承多个父类的情况),要想子类可以继承多个父类,需要通过定义接口的形式,使用implements 关键字实现。
单继承:public class Cat extends Animal{...}

多层继承:public class Cat extends Animal{...} public class DragonLi extends Cat{...}

同类继承:public class Cat extends Animal{...} public class Dog extends Animal{...}

多继承:public class BlueGolden implements BlueCat,GoldenShadedCat{...}
`public interface BlueCat {
csharp
public void eat();
} public interface GoldenShadedCat {
csharp
public void sleep();
public void play();
}`

我们这时已经知道子类有几种方式去继承父类的属性和方法了,接下来我们来了解怎么在子类中使用父类的属性和方法,我们可以使用super关键字来访问父类中的属性和方法,在举例之前会用到this关键字,这个关键字很简单,this是指向当前对象,通过this可以引用当前对象的属性和方法。
这是父类:
`public class Animal { protected String name = "Animal"; public int age = 100; public Animal() {//无参构造 this.name = "one"; this.age = 0; }
csharp
public Animal(String name, int age) {//有参构造
this.name = name;
this.age = age;
}
public void play() {
System.out.println("Animal play method");
}
public String getMessage() {
return "Animal message";
}
}`
这是子类:
`public class Cat extends Animal{ private String name = "Cat"; private int sex = 0; public void printNames() { System.out.println("Cat name: " + this.name); // 访问子类属性 System.out.println("Animal name: " + super.name); // 访问父类属性 } @Override public void play() { super.play(); // 调用父类的play方法 System.out.println("Cat play method"); } public void showMessage() { String AnimalInfo = super.getMessage(); // 调用父类方法 System.out.println("Animal show: " + AnimalInfo); } public Cat() { super(); // 调用父类的无参构造方法(可省略,编译器会自动添加) this.sex = 1; }
arduino
public Cat(String name, int age, int sex) {
super(name, age); // 调用父类的有参构造方法
this.sex = sex;
}
}`
我们来测试一下: `public class StartDemo { public static void main(String[] args) { Cat cat = new Cat("小猫咪",1,0); System.out.println("@@@@@@@@@@@@@@@@@@@printNames@@@@@@@@@@@@@@@@@@@@@@"); cat.printNames(); System.out.println("@@@@@@@@@@@@@@@@@@@@@play@@@@@@@@@@@@@@@@@@@@"); cat.play(); System.out.println("@@@@@@@@@@@@@@@@@@@@@showMessage@@@@@@@@@@@@@@@@@@@@"); cat.showMessage();
}
}`

在使用super关键字时要注意重要的几项:
①子类访问父类构造方法时super要放在子类构造方法的第一行的位置
`public class Cat extends Animal{ private String name = "Cat"; private int sex = 0;
arduino
public Cat(String name, int age, int sex) {
super(name, age); // 调用父类的有参构造方法
this.sex = sex;
}
}`
②调用父类的无参构造方法(super可省略,编译器会自动添加)
`public class Cat extends Animal{ private String name = "Cat"; private int sex = 0;
csharp
public Cat() {
super(); // 调用父类的无参构造方法(可省略,编译器会自动添加)
this.sex = 1;
}
}`
③父类没有无参构造方法时,子类访问父类时要使用super调用父类的有参构造方法
`public class Animal { protected String name = "Animal"; public int age = 100; //未定义无参构造 public Animal(String name, int age) {//有参构造 this.name = name; this.age = age; }
} public class Cat extends Animal{ private String name = "Cat"; private int sex = 0; public Cat(String name, int age, int sex) { super(name, age); // 调用父类的有参构造方法 this.sex = sex; }
}`
④子类静态方法不能使用super的方式调用父类的属性和方法,要用"父类类名."的方式调用
class Cat extends Animal { public static void staticMethod() { // System.out.println(super.name); // 编译错误:不能在静态方法中使用super System.out.println(Animal.name); // 正确方式:通过类名访问 } }
那么说完super访问父类对象后,我们可以思考一下,父类能不能控制一下子类不能随便继承呢?这是final关键字派上用场了,final本意为最终的,最后的,完成的。
接下来我们使用final关键字修饰一下Animal并测试一下看看效果:


我们可以看到被final修饰的类,不能被继承,此外如果一个类中的属性或方法被final修饰了,属性就不能被改成其他值,方法也不能被重写,如果一个类被final修饰,其中的属性和方法没有被final修饰的话,那么其中的属性可以被改值,方法可被重写。
学到这里,子类和父类的关系我们基本上搞清楚了,一个父类一般有多个子类,父类的属性和方法有通用性的表现,如果一个子类要实现通用性,就可以从子类对象向上转型为父类类型;如果一个父类对象要使用子类特有的属性和方法就需要向下转型为子类类型。
向上转型:

向上转型可以访问父类的方法:

向下转型:

运行上边向下转型的代码居然跑报错了:

为什么会报错呢?因为一开始使用Cat向上转型为Animal,那么向下转型应该也要转型为Cat,如果强行向下转型为Dog的话,Animal无法访问到Dog中的属性和方法就会报错,正确的形式我们应该做安全验证,防止向下转型时报错,影响程序正常运行,一般使用 instanceof关键字。

加了安全验证后的运行效果,其实代码只运行了else if中Animal向下转型为Cat的逻辑:

向上转型是经常使用的,向上转型能提高代码的复用性和维护性;向下转型是不经常使用的,向下转型一般是需要调用子类特有的属性和方法才会使用。
好了,继承到这已经学的差不多了,总之还是那句话:延续和发展其实就是继承一部分。
最后,码字不易,如果大家觉得文章还行,还请大家关注或点上小红心,大家一起进步,也祝大家前程似锦。