继承是类的一个很重要的特性,什么?你连继承都不知道?你是想气死爸爸好继承爸爸的遗产吗?(滑稽)
开个玩笑,这里的继承跟我们现实生活的中继承还是有很大区别的,一个类可以继承另一个类,继承的内容包括属性跟方法,被继承的类被称为父类或者基类,继承的类称为子类或者导出类,在子类中可以调用父类的方法和变量。在 java 中,只允许单继承,也就是说 一个类最多只能显示地继承于一个父类。但是一个类却可以被多个类继承,也就是说一个类可以拥有多个子类。这就相当于一个人不能有多个父亲一样(滑稽,老王表示不服)。
话不多说,先看栗子:
public class Employee {
private String name;//姓名
private double salary;//薪水
//构造函数
public Employee(String name,int age,double salary){
this.name = name;
this.age = age;
this.salary = salary;
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
public int getAge() {
return age;
}
}
我们定义了一个 Employee 类(雇员类),并定义了一些简单的成员变量以及方法,接下来定义一个 Manager 类(经理类)来继承这个类。
public class Manager extends Employee{
private double bonus;//奖金
//构造器
public Manager(String name, double salary){
super(name,salary);
bonus = 0;
}
//设置奖金
public void setBonus(double bonus) {
this.bonus = bonus;
}
//重载父类的getSalary方法
@Override
public double getSalary() {
double baseSalary = super.getSalary();
return baseSalary + bonus;
}
}
这里需要说明的是 super 跟 this 的使用,super 是父类引用,可以用它来调用父类的方法和属性,可以把它看作是父类跟子类沟通的桥梁,而 this 则是自身引用,可以通过它来调用自身的属性和方法,在构造器中我们使用了 super(name,salary); 这样会调用父类的构造函数,
为什么 Manager 可以继承 Employee 这个类呢?是因为它们之间存在 is-a 的关系,经理也是一个雇员,有很多跟雇员相同的属性如姓名,薪水,以及方法,如取姓名,取薪水,但是它也有自己独有的属性和方法,还可以重载父类的方法,如上面的 getSalary。这里的 Manager 类对象,继承了父类 Employee 的方法,因此 Manager 对象可以直接使用 getName() 方法,重载了 getSalary 方法,因此调用 Manager 对象的该方法时,调用的是子类的 getSalary 方法,而不是父类,
那到底可以继承父类的哪些信息呢?
1. 子类可以继承父类的成员变量
当子类继承了某个类之后,便可以使用父类中的成员变量,但是并不是完全继承父类的所有成员变量。具体的原则如下:
1)能够继承父类的 public 和 protected 成员变量;不能够继承父类的 private 成员变量;
2)对于父类的包访问权限成员变量,如果子类和父类在同一个包下,则子类能够继承;否则,子类不能够继承;
3)对于子类可以继承的父类成员变量,如果在子类中出现了同名称的成员变量,则会发生隐藏现象,即子类的成员变量会屏蔽掉父类的同名成员变量。如果要在子类中访问父类中同名成员变量,需要使用 super 关键字来进行引用。
2. 子类继承父类的方法
同样地,子类也并不是完全继承父类的所有方法。
1)能够继承父类的 public 和 protected 成员方法;不能够继承父类的 private 成员方法;
2)对于父类的包访问权限成员方法,如果子类和父类在同一个包下,则子类能够继承;否则,子类不能够继承;
3)对于子类可以继承的父类成员方法,如果在子类中出现了同名称的成员方法,则称为覆盖,即子类的成员方法会覆盖掉父类的同名成员方法。如果要在子类中访问父类中同名成员方法,需要使用 super 关键字来进行引用。
这里说了很多次 public,private 和 protected,关于访问权限好像没还有正式介绍,这里来顺便简单介绍一下吧:
Java 类具有三种访问控制符:private、protected 和 public,同时当不写这三个访问控制符时,表现为一种默认的访问控制状态。因此,一共具有四种访问控制级别。
具体访问控制表现如下:
private 修饰的属性或方法为该类所特有,在任何其他类中都不能直接访问;
default 修饰的属性或方法具有包访问特性,同一个包中的其他类可以访问;
protected 修饰的属性或方法在同一个中的其他类可以访问,同时对于不在同一个包中的子类中也可以访问;
public 修饰的属性或方法外部类中都可以直接访问。
为什么要引入访问权限这个概念呢?当然是为了更好的封装,就像制作一台机器一样,自然希望把所有的电线都藏在盒子里而不是大摇大摆的吊在外面被人吐槽,而且这样也更加安全,只给用户或用户程序员看那些想给他们看的内容就好了,其他的一律隐藏起来。
子类 Manager 虽然没有继承父类 Employee 的 name 和 salary 属性,但不代表对这两个属性的操作没有意义,可以理解成一个子类对象中包含有一个父类对象,打个比方,就像是我们组装好几款不同的电脑,为了方便起见可以选用同一款主机箱,里面配置了相同的电源和风扇,而其它的配置每台电脑都可以不一样,甚至如果需要的话,某些电脑还可以更换一下风扇和电源,虽然最后性能可能相去甚远,但是从外表上看起来,它们都是差不多的。(当然,如果你非要改装的完全不一样也是可以的)这里的配置好风扇跟电源的主机箱就相当于我们的父类,而不同的电脑就相当于子类,子类可以调用父类的公开方法,如转动风扇,但不能直接改变主机箱的颜色,因为父类并没有提供这样的权限。但这不代表主机箱的颜色对于子类没有用,它仍属于子类的一部分,只是不能直接操作它罢了。
访问权限的内容就介绍到这里了,现在回归到我们的继承上来,下面是使用 Manager 类的一个栗子:
public class ManagerTest {
public static void main(String[] args){
Manager boss = new Manager("Frank",100000);//定义一个Manager变量
boss.setBonus(10000);//设置奖金
Employee[] staff = new Employee[3];//创建一个Employee数组
//给数组赋值
staff[0] = boss;
staff[1] = new Employee("Alan",8000);
staff[2] = new Employee("Tom",9000);
//遍历输出数组元素
for (Employee e:staff)
System.out.println("name:"+e.getName()+" salary:"+e.getSalary());
}
}
这里我们定义了一个 Employee 数组,然后把一个 Manager 变量赋值给了 Employee 数组的第一个元素,看到这里,你也许会感到疑惑,不是说只能在相同类型的变量之间使用赋值操作吗?确实如此,但是因为 Manager 类是 Employee 的子类,一个 Manager 对象同时具有 Employee 的所有属性跟方法,也就是说 Employee 能做的事情,它也同样能做,所以,把 Manager 类的变量赋值给 Employee 变量是没有问题的,但反之则不行,因为 Manager 类有它自己的方法 setBonus(),Employee 是无法实现。在遍历输出的时候,我们把所有元素都当成 Employee 对象来使用,输出如下:
name:Frank salary:110000.0
name:Alan salary:8000.0
name:Tom salary:9000.0
我们 boss 变量,在调用 getSalary 方法的时候,显然是调用了子类的方法,将基本薪水加上了奖金之后才进行返回。
那说了这么多,为什么非要使用继承呢?
原因很简单,一个是可以实现代码的复用,像这个例子一样,Employee 的 getName 方法被子类 Manager 复用了,Manager 中可以直接使用这个方法,这样可以省去很多代码。
其次是可以实现多态,说出来你可能不信,我们刚才的栗子已经使用到了一个很伟大的概念——多态,在遍历输出的时候,一个父类对象的引用指向了子类对象,并调用了子类方法。
那么这样做的好处是什么呢?多态的意义何在?
简单,方便,继续用我们刚才的栗子,假如我们现在有一个人事管理类,PersonnelManagement,需要对员工的信息进行录入,有一个 record 方法,我们如果使用了多态的特性,只需要给 record 方法传入一个 Employee 对象即可,不管是经理还是普通雇员都能使用相同的方式进行处理,否则我们需要为经理跟雇员分别设计一个方法,这样也许觉得没事,但如果现在又多了很多其它岗位,如总经理,副经理,经理助手,人事部经理,采购部经理,这时候你还能为每个岗位设计一个方法吗?显然不现实,而且这样就失去了可扩展性跟灵活性,把一门艺术活变成了体力活,这样会让你丧失对编程的乐趣。
所以,继承跟多态其实也很简单,继承就是使用 extends 来继承父类的属性跟方法,多态则是可以在合适的时候将子类对象视为父类对象进行统一处理,从而实现和增加代码的复用度,让你的代码越来越风骚。
至此类的继承与多态就讲解完毕了,欢迎大家继续关注!喜欢我的教程的话记得动动小手点下推荐,也欢迎关注我的博客。