在JAVA的学习过程中我们经常会用到类的继承。那么到底什么是类的继承呢?它又有哪些作用呢?今天我们从以下几个方面来认识一下类的继承。
一、为什么需要使用继承?
- 用于表示现实中存在的子集间的包含关系
比如: 学生 包含 大学生、高中生、初中生;
- 减少重复的代码;
当我们在实现大学生、高中生、初中生的类时,我们会发现这些类中有很多相似代码,比如name属性,study方法等,如果我们只是单纯地去逐个实现这些类,就会出现大量的重复代码。如果我们能把他们这些相同的属性和方法封装成一个父类,要用的时候再去父类那里拿,这样就可以减少很多重复的代码。
- 提高程序的扩展性。
我们在实现一个类的时候并不是说这个类就是固定的,不会再改变。实际上由于现实情况的改变,我们进行要去改变这些类。比如说我们现在要给所有的学生增加一个学号属性。通常的方法就是找到所有不同的学生类,逐个去增加这个属性。但是这样子的话效率会很低。但是如果我们有一个他们共同的父类。我们只要去给这个父类增加学号属性就OK了,明显可以节省很多的工作量。
二、JAVA继承的语法格式
- JAVA中类继承的关键字:extends
- 格式:
public class 类名(子类、派生类、超类) extends 类名(父类、基类){
}
- 注意:Java中类的继承是单继承,一个子类只能继承一个父类,但是一个父类可以被多个子类继承。
三、子类能继承到父类的哪些内容?
子类能够继承到父类所有的属性和普通方法。(注意:无法继承构造方法)和父类中的属性和方法的修饰符无关。访问修饰符是用来限制属性和方法的使用范围,而不是继承。
除了继承父类已有的属性和方法,子类还可以自己定义父类没有的属性和方法。
四、方法重写
为什么需要方法重写?因为父类中定义的某个方法子类也要用,但是子类方法的具体实现和父类不同。
进行方法重写的条件:
- 必须存在继承关系
- 在重写方法时,子类方法的访问修饰符可以大于或等于父类方法的访问修饰符
- 在重写方法时,子类方法的返回值数据类型,方法名,参数都必须和父类的一致
- 方法中的代码肯定要不同
那我们在子类中进行方法重写之后如何确定我们调用的是谁的方法呢?这时我们就需要根据new关键字后的类名来决定,如果new后面的类名是子类,那么就调用子类的方法。如果是父类,就调用父类的方法。我们看下面的例子。
构造一个Student父类。UNStudent子类。子类中重写父类中的study方法。
运行结果
在这里尽管new前面的是父类名,但是因为new后面的类名是子类,所以我们就会调用子类中重写的study方法。
但是如果我们这时想要执行父类的方法怎么办?这就需要一个关键字super。
运行结果
发现我们调用到父类的方法了。
五、自动转型
我们在前面讲述第四点的时候其实已经用到了自动转型。自动转型的格式如下:
父类名 对象名 = new 子类构造方法(参数值)
当然要使用自动转型,前提是必须存在继承关系。
自动转型这个机制有好也有坏。我们来看一下它的不足之处。如果我们使用了自动转型,又尝试调用子类中有的但是父类中没有的属性和方法,这个时候就会报错。我们看一下下面的例子
score是一个子类中新增的属性,当我尝试去调用它时,发现报错了。这是因为JAVA的机制导致的,JAVA在编译时,它会将你调用到的函数名去new前面的那个类名中查找。在我们这个例子中就是取Student中查找,而不是UNStudent。这时再父类中它找不到score这个属性自然会报错。那这个问题怎么解决呢?有两种方法:
- 方法一,如下图,增加一段强制转型的代码。然后用sun对象去调用score属性。
//自动转型中掉子类中独有的元素和方法
UNStudent sun=(UNStudent)st;
sun.score=50;
- 方法二,不显示地去使用自动转型。直接使用 UNStudent st= new UNStudent();等你需要用到自动转型的时候让JAVA默认去转。具体的例子看后面。
可能有人会觉得既然自动转型存在问题,那我们为何还要用它。一个简单的原因就是这种机制可以很好地解决现实中存在的一些场景问题。我们看以下的例子。
场景:**老师正在教大学生英语,显然这位老师也可以教小学生、初中生、高中生英语。下面我们尝试用普通的方法来写一下代码。
如果学生的类别继续增加,增加到100种,1000种呢?那我们的代码就会变得特别长。如何减少代码量呢。这里自然就要用到自动转型了。我们为这些不同类别的学生构造一个Student父类。Teacher类的代码缩减如下:
我们在teacher类中添加了一个入口,展示了具体的调用过程。
其中对象st2和使用了我们前面所讲的自动转型。因此不能直接调用GZStudent这个类中的独有的方法。st1我们咋一看好像没有使用自动转型。但实际上它也用了自动转型。因为在te对象调用teach方法的时候,teach方法中的参数原本应该是Student,但是这里我们传进去的是UNStudent,它实际上已经悄悄进行了一次自动转型。这种隐式转型的方法有一个好处,它是可以直接调用子类中独有的方法而不会报错。
最后我们再来讲一下两个小概念。一个是多态。即多种状态。接口的多种不同的实现方式即为多态。多态是方法重载、继承、方法重写、自动转型这些技术的特性。另一个是封装。包、类、属性、方法、访问修饰符等都是封装。通俗地讲就是我把一些东西组合成一个黑匣子,实现一些功能,并告诉你功能怎么用,但是具体的实现你看不到。
至此,我们已经把类的继承讲得差不多了。