java基础——day07-1 继承、super、this、抽象类
继承
概述
多个类中存在相同的属性和行为,将这些内容抽取到单独的一类中,那么多个类无需再定义这些属性和行为,只需要继承单独抽象出来的那个类即可。
例如:生活中的继承
从图中,我们可以了解到,兔子和羊属于食草类动物,狮子和豹子属于食肉类动物,而食肉动物和食草动物又属于动物类
其中,多个类可以称为子类,单独那一个类成为父类、超类(superclass)或者基类
定义
继承:就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性(成员变量)、相同的行为(成员方法)。子类可以直接访问父类中的非私有的属性和行为。(例如父亲的姓名、父亲会打球 你不能继承)
好处
1、提高代码复用性
2、类与类之间产生了关系,是多态的前提
继承的格式
通过extends关键字,可以声明一个子类继承一个父类,例如:
演示:
package day07.demo01; //父类 -- 员工 public class Employee { //定义员工类 //成员变量 String name; int age; //成员方法 public void work(){ System.out.println("方法执行"); } }定义一个父类-员工
package day07.demo01; //定义了一个员工的子类:教师 其继承父类 extends public class Teacher extends Employee { }定义教师类 继承员工类
package day07.demo01; public class Assistant extends Employee { //定义员工的另一个子类 -助教 }定义员工第二个子类--助教
package day07.demo01; /** * 子类就是父类 is-a 教师就是员工 */ public class day07_1 { public static void main(String[] args) { //创建子类对象 Teacher teacher = new Teacher(); //子类继承了父类"工作"的成员方法 teacher.work(); //创建员工另外一个对象--助教 Assistant assistant = new Assistant(); //助教调用员工(父类)的工作(成员)方法 assistant.work(); } }main函数
特点:提高代码的复用性
关系:is -a
继承后的特点——成员变量
1.成员变量不重名
如果子类和父类中出现不重名的成员变量,这时访问是没有影响的,例如:
package day07.demo01.demo02; public class Fu { //创建父类成员变量 int numFu = 10; }Fu
package day07.demo01.demo02; //创建子类—Zi 继承父类—Fu public class Zi extends Fu { //定义子类的成员变量 int numZi = 20; /** * 此处子类含有两个成员变量 * 一个是自己定义的numZi * 一个是继承Fu的numFu */ }Zi
package day07.demo01.demo02; public class demo01 { public static void main(String[] args) { //创建一个父类对象 Fu fu = new Fu(); System.out.println(fu.numFu); //只能使用父类的东西,没有任何子类的东西 //创建一个子类对象 Zi zi = new Zi(); System.out.println(zi.numFu);//可以访问父类的成员变量 System.out.println(zi.numZi);//也可以访问自定义的成员变量 } }main
2.成员变量重名
如果子类和父类中出现重名的成员变量,这时访问是有影响的。例如:
package day07.demo01.demo03; public class Fu { int num = 10; public void methodFu(){ //访问的是父类中的num System.out.println("fu:"+num); } }Fu
package day07.demo01.demo03; //创建子类—Zi 继承父类—Fu public class Zi extends Fu { int num = 20; public void methodZi(){ //访问的是子类的num 因为num里面有 System.out.println("zi:"+num); } public void show(){ //访问父类中的num System.out.println("子类访问父类的num:"+super.num); //访问子类自己的num System.out.println("子类访问自己的num:"+this.num); } }Zi
package day07.demo01.demo03; /** * 子父类成员变量重名情况 * 直接:等号左边是谁,没有则向上找 * 间接:该方法属于谁 就优先用谁 没有则向上找 */ public class demo { public static void main(String[] args) { Fu fu = new Fu(); fu.methodFu(); Zi zi = new Zi(); System.out.println(zi.num); //直接访问子类 子类优先 20 没有则找父类的 zi.methodZi(); System.out.println("---------------------"); zi.show(); } }main
注意:子父类出现同名成员变量时,在子类中访问父类中非私有成员变量时,要使用super关键字,修饰父类成员变量,类似与this关键字。
使用格式:super.父类成员变量名(子父类同名变量名)
3.访问private修饰的父类成员变量
当使用private(私有)修饰父类成员变量,那么如何访问父类私有成员变量?
package day07.demo01.demo04; public class Fu { //使用private修饰父类成员变量 private String name = "张若筠"; private int age = 28; //这时需要通过get and set方法访问 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }Fu
package day07.demo01.demo04; //子类继承父类 public class Zi extends Fu { public void show(){ //访问父类的Name成员变量(属性) System.out.println(this.getName()); //访问父类的name成员变量(属性) System.out.println(this.getAge()); } public void setFu(){ //修改父类的姓名属性(一般不建议) this.setName("海燕"); this.setAge(40); } }Zi
package day07.demo01.demo04; public class demo { public static void main(String[] args) { //创建一个子类对象 Zi zi = new Zi(); //调用子类访问父类的成员方法 zi.show(); //调用子类修改父类的成员方法 zi.setFu(); //打印修改后的父类 zi.show(); } }main
我们可以通过getter and setter去访问父类的私有成员变量,但是关于setter要根据事情进行添加
继承后的特点——成员方法
1.成员方法不重名
如果子类和父类中出现不重名的成员方法,这时调用不会有影响
package day07.demo01.demo05; public class Fu { //子父类成员方法不重名 public void method(){ System.out.println("我是父类中的成员方法"); } }Fu
package day07.demo01.demo05; //继承 public class Zi extends Fu{ public void methodZi(){ System.out.println("我是子类中的成员方法"); } }Zi
package day07.demo01.demo05; //子类和父类的成员方法 不重名 public class demo { public static void main(String[] args) { Zi zi = new Zi(); //子类调用父类的成员方法 zi.method(); //子类调用自己的成员方法 zi.methodZi(); } }main
2.成员方法重名——重写(override)
如果子类和父类中出现重名的成员方法,这时访问是一种特殊情况,叫做方法重写(override)
方法重写:子类中出现和父类一模一样的方法时(返回值类型,方法名和参数列表相同),会出现覆盖效果,也称为重写或复写。声明不变,重新实现。
特点:创建的是子类对象,则优先用子类方法(创建的是父类对象 则优先用父类的方法)
package day07.demo01.demo06; public class Fu { //创建父类的成员方法 public void method(){ System.out.println("我是父类中的方法"); } }Fu
package day07.demo01.demo06; //继承 public class Zi extends Fu { //定义子类中的成员方法 方法重写 public void method(){ System.out.println("我是子类中的成员方法--override"); } }Zi
package day07.demo01.demo06; public class demo { public static void main(String[] args) { //创建一个子类对象 Zi zi = new Zi(); //特点:创建的是子类对象,所以优先选择子类的方法 所以输出override zi.method(); //创建一个父类对象 Fu fu = new Fu(); fu.method(); // 创建的是一个父类对象 优先选择父类的方法 } }main
对比:
方法重写(override):发生在继承关系中,方法名称一样,参数列表也一样
方法重载(overload):方法名称一样,参数列表不一样
重写的应用(完善父类的缺陷)
子类可以根据需求,定义特定自己的行为。比如手机增加来电显示头像的功能
package day07.demo01.demo07; //创建手机 父类 public class phone { //创建父类的发送短信的功能 public void SendMessage(){ System.out.println("发短信"); } public void call(){ System.out.println("打电话"); } public void showNum(){ System.out.println("来电显示"); } }父类-phone
package day07.demo01.demo07; //继承父类 phone public class newPhone extends phone { //新增来电显示姓名和头像 //重载phone的电话功能 @Override public void call(){ //调用父类原始的大电话功能 super.call(); //增加自己新的功能——显示姓名和头像 System.out.println("显示来电姓名"); System.out.println("显示来电头像"); } }子类-newPhone
package day07.demo01.demo07; public class demo { public static void main(String[] args) { //创建一个newphone对象 newPhone iphone = new newPhone(); iphone.SendMessage();//子类调用父类发短信功能 iphone.showNum();//子类调用父类 打电话的功能 iphone.call();//子类调用重写功能 } }main
注意事项:
1.子类覆盖父类方法时,必须保证权限小于等于父类权限
2.子类覆盖父类方法,返回值类型、函数名和参数列表要一模一样
继承后的特点——构造方法
构造方法的格式和定义:
格式:
public 构造方法名(){} //无参数的构造方法
1.子类构造方法当中有一个默认隐含的“super()”调用,所以一定是先调用父类构造,后执行子类构造。
2.子类构造可以通过super关键字调用父类重载构造(例如一个无参一个有参的构造方法)
3.super的父类构造调用,必须是子类构造方法的第一个语句。即一个子类构造不能多次super构造。
父类无参构造:
package day07.demo01.demo08; public class Fu { //定义父类无参构造方法 public Fu(){ System.out.println("父类的构造方法"); } }Fu
package day07.demo01.demo08; //继承 public class Zi extends Fu{ //定义子类无参数构造方法 public Zi(){ System.out.println("this is Zi constractor"); } }Zi
package day07.demo01.demo08; public class demo { //继承中的构造方法 public static void main(String[] args) { //创建子类对象 Zi zi = new Zi(); //发现其先执行了父类的构造方法 再执行子类的构造方法 } }main
父类含参构造:
package day07.demo01.demo08; public class Fu { //定义父类无参构造方法 public Fu(){ System.out.println("父类的无参构造方法"); } public Fu(int num){ System.out.println("父类有参构造方法"); System.out.println(num); } }含参-Fu
package day07.demo01.demo08; //继承 public class Zi extends Fu{ //定义子类无参数构造方法 public Zi(){ super(10); //调用父类有参构造方法 System.out.println("this is Zi constractor"); } }Zi
package day07.demo01.demo08; public class demo { //继承中的构造方法 public static void main(String[] args) { //创建子类对象 Zi zi = new Zi(); //发现其先执行了父类的构造方法 再执行子类的构造方法 } }main
super和this
父类空间优先于子类对象的产生
在首次创建子类对象时,先初始化父类空间,再创建其子类本身。目的在于子类对象包含了其对应的父类空间,所以先创建父类空间,子类就能获得父类的成员、方法。
若父类成员非private修饰,则子类可以随意使用父类成员。代码体现在子类的构造方法调用时,一定会先调用父类的构造方法。(比如说:没有爹 哪来的儿子能继承的财产)
super和this的含义
super:代表父类的存储空间标识(可以理解为父亲的引用)
this:代表当前对象的引用(谁调用代表谁)
super和this的用法
1.访问成员
this.成员变量 //本类的
super.成员变量 //父类的
this.成员方法名() //本类的
super.成员方法名() //父类的
2.例如
package day07.demo01.demo09; public class Animal { //定义动物类的成员变量 String name; int age; //定义动物类的成员方法 public void eat(){ System.out.println("Animal:eat"); } }动物类
package day07.demo01.demo09; //定义猫类 继承父类 Animal public class Cat extends Animal{ //eat方法重载 @Override public void eat() { //方法重载 System.out.println("eat fish"); } //定义猫类自己的成员方法 public void eatTest(){ super.eat();//---super调用父类的方法 this.eat();//----this调用本类的方法 } }猫类
package day07.demo01.demo09; public class demo { public static void main(String[] args) { //实例化一个Cat对象 Cat cat = new Cat(); //继承的成员变量 cat.name = "小咪"; cat.age = 2; //调用eatTest方法 cat.eatTest(); } }main
3.访问构造方法
this(....) ----本类的构造方法(具体查看上述手机案例)
super(.....) ----父类的构造方法
1.子类的每个构造方法中均有默认的super()——调用父类的无参构造。
2.手动调用父类构造方法会覆盖默认的super()。
3.super()和this()都必须是在构造方法的第一行,所以不能同时出现(例如不能出现两个super这样会报错)。
继承的特点
1.一个类只能有一个父类,不可以有多个父类(一个孩子 只能有一个爹)
class C extends A{} //right
class C extends B,C{} //error
2.java支持多层次继承(继承体系[孩子只能有一个爹 一个爹能有多个孩子])
class Fu{}
class A extends Fu{}
class B extends Fu{}
注:*父类是Object类,所有的类默认继承Object,作为父类
3.子类和父类是一种相对的概念