第四章、Java面向对象(四)
本人也是刚入门Java语言,可能会有一些地方出现错误,描述的不对。如果发现不对的地方请及时指出,好对其进行修改。这样不仅可以让我学到东西,也可以让其他刚入门的朋友学习更正确的内容。
所有内容仅供参考。不具有完全的准确性!
注:关于Java的所有内容都会参考到尚硅谷在网上公开的学习视频及其提供的PPT
推荐:https://blog.csdn.net/dilixinxixitong2009/article/details/77962030
前言
继承不仅是计算机中的词汇,也是现实生活中的词汇。而且现实中出现继承的时间要远远早于计算机。在现实中的继承,指子女传承了父母的优良传统,继承了遗产等。就是说父母的东西(父母也有属于自己的东西,是子女无法继承的),也属于子女。在计算机中的继承和现实的继承类似。
一、面向对象三大特征之继承
(一)为什么要有继承
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
此处的多个类称为子类(派生类),单独的类称为父类(基类或超类)。
通过使用继承可以极大的减少代码的冗余
例:没有继承的情况下
class Person{
String name;
int age;
public void sleep(){
System.out.println("睡觉");
}
}
class Student{
String name;
int age;
public void sleep(){
System.out.println("睡觉");
}
}
可以看出来,上边两个类除了类名不一样,属性和方法完全一样。既然一样,就没有写两遍(或更多遍)的必要性了。此时,通过继承就很好的解决了
例:使用继承的情况
class Person{
String name;
int age;
public void sleep(){
System.out.println("睡觉");
}
}
class Student extends Person{
}
这就可以了。现在的Student和上边没有使用继承的Student的内容是完全一样的。
(二)什么是继承
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为和属性。
(三)如何使用继承
语法格式:
class A extends B{ }
A:子类、派生类、subclass
B:父类、超类、基类、superclass
通过关键字extends 可以实现类的继承
例:
class Student extends Person{
}
说明:
- 一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有的属性和方法。特别的,父类中声明为private的属性或方法,**子类继承父类以后,仍然认为获取了父类中私有的结构。**只是因为封装性的影响,使得子类不能直接调用父类的结构而已。可以通过父类其他方法间接调用父类私有方法。
- 子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展。(子类的功能要比父类强大)
- 子类和父类的关系,不同于子集和集合的关系。
例:关于子类使用父类中的私有结构
class Person{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private void eat(){
System.out.println("吃饭");
}
public void sleep(){
eat();
System.out.println("睡觉");
}
}
class Student extends Person{
public void message(){
//错误的:
// System.out.println("你的名字:" + name);//由于父类中对name属于进行了封装,直接调用编译会报错
//正确的:
System.out.println("你的名字:" + getName());//此时编译和运行都不会报错了
}
public void walk(){
// eat();//此时和上边的name情况一样,编译报错
//不过我们可以通过sleep()方法间接调用eat()方法
sleep();
}
}
规定:
- 一个类可以被多个子类继承
- Java中类的单继承性,一个类只能继承一个父类。(单继承性)
- 子父类是相对的概念。
- 子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类
- 子类继承父类后,就获取了直接父类以及所有间接继承的父类中的属性和方法
注意:
- 如果我们没有显示的声明一个类的父类,则此类继承于java.lang.Object类(Object类上边不再有父类)
- 所有的java类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类
- 意味着,所有的java类都具有java.lang.Object类中声明的功能
(四)继承的作用
作用:
- 继承的出现减少了代码冗余,提高了代码的复用性。
- 继承的出现,更有利于功能的扩展。
- 继承的出现让类与类之间产生了关系,提供了多态的前提。
注意:不要仅为了获取其他类中某个功能而去继承
二、方法的重写
(一)为什么要重写
当子类对所继承的父类中的某个方法不满意时,子类可以将这个方法重新声明在自己的类中,将方法体改成自己满意的。
(二)什么是重写
在子类中可以根据需要对从父类中继承来的方法进行改造,也称为方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。
(三)如何使用重写
- 子类重写的方法必须和父类被重写的方法具有相同的方法名称、参数列表
- 子类重写的方法的返回值类型不能大于父类被重写的方法的返回值类型
- 子类重写的方法使用的访问权限不能小于父类被重写的方法的访问权限
- 子类不能重写父类中声明为private权限的方法
- 子类方法抛出的异常不能大于父类被重写方法的异常
注意:子类与父类中同名同参数的方法必须同时声明为非static的(即为重写),或者同时声明为static的(不是重写,且static修饰的方法不能被重写)。因为static方法是属于类的,子类无法覆盖父类的方法。
例:
class Person{
public void eat(){
System.out.println("我喜欢吃麻辣烫");
}
}
class Student extends Person{
//我喜欢吃火锅,我要重写eat()
public void eat(){
System.out.println("我喜欢吃火锅");
}
}
补充:
-
子类重写父类的方法以后,父类再调用该方法的时候,就是被重写后的方法。
子类若要继续调用被重写前的父类中的方法,就需要用到super. 来调用
this.test(); //子类中调用子类方法
super.test();//子类调用父类方法
父类若要调用被重写前的方法:需要创建一个本类的对象,通过对象名调用被重写前的方法 -
当父类中show方法声明为private权限的时候,子类无法重写该方法,但子类可以定义和父类中private修饰的方法完全一样(权限、返回值、方法名和形参列表一样)的show方法,子类中的该方法的权限修饰符可以任意设置。
因为这两个方法没有任何关系,子类中的show方法和父类中的show方法是两个互不相干的方法,同时,这种也完全不是重写 -
重写时对返回值类型的要求:
若父类中的返回值类型为void,则子类重写时的返回值类型也必须时void
若父类中的返回值类型为A类,则子类重写时的返回值类型可以是A类或A类的子类(这里的A类和子类都是引用数据类型)
若父类中的返回值类型为基本数据类型,则子类重写时的返回值类型也必须是相同的基本数据类型(和类型转换无关)
注意:这里的数据类型和类型转换不牵扯,父类为double时,子类也必须为double -
重写时抛出的异常类型要求:
子类重写的方法抛出的异常类型不大于父类被重写的方法抛出异常类型
面试题:
重载和重写的区别:
首先重载和重写没有任何关系,只是名字相似。
重载是方法名相同,而形参列表不同(只有返回值不同不算重写—编译也会报错)。
重写是在子类中重新声明父类中的方法,要求方法名和形参列表完全一样。
三、super关键字的使用
- 在Java类中使用super来调用父类中的指定操作:
- super可用于访问父类中定义的属性
- super可用于调用父类中定义的成员方法
- super可用于在子类构造器中调用父类的构造器
- 注意:
- 尤其当子父类出现同名成员时,可以用super表明调用的是父类中的成员
- super的追溯不仅限于直接父类
- super和this的用法相像,this代表本类对象的引用,super代表父类的内存空间的标识
例:
class Person{
public void eat(){
System.out.println("我喜欢吃麻辣烫");
}
}
class Student extends Person{
//我喜欢吃火锅,我要重写eat()
public void eat(){
System.out.println("我喜欢吃火锅");
}
public void sleep(){
//通过super可以直接看出调用的时父类中的eat()方法
super.eat();
}
}
- 调用父类的构造器
- 子类中所有的构造器默认都会访问父类中空参数的构造器
- 当父类中没有空参数的构造器时,子类的构造器必须通过this(参数列表)或者super(参数列表)语句指定调用本类或者父类中相应的构造器。同时,只能”二选一”,且必须放在构造器的首行。(this和super不能同时出现在一个方法中,且只能出现一次)
- 如果子类构造器中既未显式调用父类或本类的构造器,且父类中又没有无参的构造器,则编译出错
补充:
当父类中没有空参构造器时,处理方法:
- 在父类中添加一个空参构造器
- 子类的任一构造器中调用父类中定义过的任一构造器
例: