java09 继承(覆盖重写、super、this)抽象类
3.继承
继承是多态的前提,面向对象的三大特征:封装、继承、多态
继承可以理解为抽取共性的关键点,如上图所示。
定义:
父类: public class 父类名称{ 子类:public class 子类名称 extends 父类名称{
代码块 代码块
} }
唯一一个标识 extends 。
从而实现了代码复用的作用。
3.0.1.父类与子类的成员变量各自使用范围:
父类可以使用父类的成员变量,而子类不光可以使用子类成员变量 还可以使用父类的成员变量。父类与子类成员变量可以重名。
3.0.2.访问父类成员变量的方法:
- 直接通过子类对象访问成员变量:
规则:等号左边是谁,则优先用谁,否则没有则向上查找。
- 间接通过成员方法访问成员变量:
规则:子类对象点(调用)的方法是谁,则优先使用谁,没有则向上找。
至此,出现三种变量:局部变量、子类成员变量、父类成员变量,因此在子类的成员方法中进行以下三种方法区分:即
局部变量直接用,子类成员变量用this.,
而父类成员变量用super进行区分。
调用成员方法的对象是子类,则优先用子类的成员方法,否则就向上找。
3.1.继承关系中成员方法名称一样就存在覆盖重写
覆盖重写:override 发生在继承关系中,方法名称一样,参数列表也一样,
方法重载:overload 方法名称一样,参数列表不同。
3.1.1.方法的覆盖重写使用过程中有几点需要特别十分关注
- 父类与子类的成员方法,必须同名和同参数,可使用@override起到安全检测作用。
- 子类的返回值范围必须小于父类的返回值。
- 子类的方法权限必须大于等于父类的方法权限 public>protected>(default)>private
3.1.2.方法的覆盖重写的应用场景
假如 现在有个需求,将老款手机中的来电提醒功能,增加手机姓名等,这时不方便写过去所有用户的老程序,此事扩展其新方法,就需要使用覆盖重写的子类方法。
3.1.3父类构造方法的访问特点:
1 public class Student 2 { 3 public String name; 4 public int age; 5 public Student() 6 { 7 //默认的构造方法,其中name的初值是null,age的初值是0; 8 //当然你也可以给定一个固定的值 9 //name="name"; 10 //age=20; 11 } 12 //构造方法重载,完成对应属性的初始化 13 public Student(String name,int age) 14 { 15 this.name=name; 16 this.age=age; 17 //其中name,age的初值是参数中传入的值 18 } 19 }
特点:子类构造必须调用父类构造,默认赠送super();调用无参,否则手写super(传参)调用父类有参构造也就是父类重载的构造方法。
1.子类构造方法方法体内 必须调用父类构造方法,没有明确写super():,那么将默认赠送。
2.子类构造方法可以用super关键字来调用父类重载构造
3.子类构造方法用super调用父类构造方法时,必须排行第一句
构造方法是一种特殊的方法,它是一个与类同名的方法。对象的创建就是通过构造方法来完成,其功能主要是完成对象的初始化。当类实例化一个对象时会自动调用构造方法。
构造方法和成员方法的区别
A:格式区别
构造方法和类名相同,并且没有返回类型,也没有返回值。
普通成员方法可以任意起名,必须有返回类型,可以没有返回值。
B:作用区别
构造方法用于创建对象,并进行初始化值。
普通成员方法是用于完成特定功能的。
C:调用区别
构造方法是在创建对象时被调用的,一个对象建立,只调用一次相应构造函数。
普通成员方法是由创建好的对象调用,可以调用多次
3.2.super关键字用法
- A 子类的成员方法中,super调用父类的成员变量 super.父类成员变量名
- B 子类的成员方法中,super调用父类的成员方法 super.父类成员方法名
- C 子类的构造方法中,super调用父类的构造方法 super(可传参);
super :代表父类的存储空间标识(可以理解为父亲的引用)。 也就是使用super关键字访问父类内容。它与this关键字的区别如下:
this.成员变量 ‐‐ 本类的
super.成员变量 ‐‐ 父类的
this.成员方法名() ‐‐ 本类的
super.成员方法名() ‐‐ 父类的
3.3.this关键字
3.3.1含义
this :代表当前对象的引用(谁调用就代表谁)。 也就是使用this关键字访问本类中,或是子类中使用或是父类中使用。
this.成员变量 ‐‐ 本类的
super.成员变量 ‐‐ 父类的
this.成员方法名() ‐‐ 本类的
super.成员方法名() ‐‐ 父类的
3.3.2this关键字的3个用法和4个关键点
- 用法:
在本类的成员方法中,访问本类的成员变量
在本类的成员方法中,访问本类的另外一个成员方法
在本类的构造方法中,访问本类的另外一个构造方法
- 关键点:
this调用也得是构造方法中的第一个语句。
构造方法中,this调用不能没有尽头,至少有一个构造方法中没有调用this。
成员方法中,this可以在全部成员方法循环调用。
效果图如下:
1 package d.d.d; 2 public class zi extends fu { 3 int num =20; 4 public void showNum(){ 5 int num = 10; 6 System.out.println(num);//局部变量,访问本方法中局部变量 num = 10; 7 System.out.println(this.num);//this关键字访问本类的成员变量num = 20 8 System.out.println(super.num);//super关键字访问父类num = 30 9 } 10 public void methodA() { // 成员方法A 11 System.out.println("aaa"); 12 this.methodB(); 13 } 14 public void methodB() { // 成员方法B 15 methodA();//在成员方法methoB中调用methodA,另外一种方法是this.methodA();是强调作用 16 this.methodA();//与methodA();一样,只是起到强调作用 17 System.out.println("bbb"); 18 } 19 public zi(){ // 构造方法zi(); 20 //this.zi(); 这种是错误写法 21 this(123);//本类的无参构造,调用本类的有参构造 22 } 23 public zi(int n){ // 构造方法zi(n); 24 this(12,3); 25 } 26 public zi(int n,int b){ // 构造方法zi(n,m); 27 //this(3); 不可以全部都有this,至少有一个构造方法 28 } 29 30 } 31 32
1 package d.d.d; 2 3 public class fu {//父类 4 int num = 30; 5 } 6
3.3.3.内存图的变化
1 package d.d.d; 2 3 public class demo { 4 public static void main(String[] args) { 5 zi zi = new zi(); 6 zi.show(); 7 zi.method(); 8 } 9 }
1 package d.d.d; 2 3 public class fu { 4 int num = 10; 5 public void method(){ 6 System.out.println("父类方法"); 7 } 8 } 9
1 package d.d.d; 2 public class zi extends fu { 3 int num =20; 4 @Override 5 public void method(){ //与父类成员方法一样,叫覆盖重写 6 super.method();// 调用父类成员方法 7 System.out.println("子类方法"); 8 } 9 public void show(){ 10 int num = 30; 11 System.out.println(num);// 输出局部变量,num = 30; 12 System.out.println(this.num);// 输出本类成员变量,num = 20; 13 System.out.println(super.num);// 输出父类成员变量,num = 10; 14 15 } 16 17 } 18
3.3.4java的继承的特征
- java语言是单继承,一个类的直接父类只能有唯一一个
- java语言可以多级继承
- java语言一个父类,可以有多个子类
4.抽象类
了解下什么叫抽象,假设提问一个图形的面积计算,那么对于三角形、圆形、长方形等等,均有不同的计算方法。所以这个方法是一个抽象方法,具体到一种图形就行。如果父类方法不确定如何进行,也就是具体执行方式不确定,那么就是抽象方法。
4.1.抽象方法的定义
抽象方法:就是在返回值前面加上 abstract 关键字,然后去掉大括号,直接小括号结束;
抽象类:也就是抽象方法所在的类就是抽象类,定义抽象类就是在class前面加上abstract;
语法:
public abstract class 类名{ //抽象类就是在class前面加上abstract
public abstract void eat(); //返回值前面加上 abstract 关键字,然后去掉大括号,直接小括号结束;
}
1 package e.e.e; 2 3 public abstract class E {//抽象方法 4 public abstract void eat();//抽象方法 5 //这是普通方法 6 public void normamethod(){ 7 8 } 9 }
4.2.抽象方法的使用方法和注意事项
- 不能直接创建new抽象类对象
- 必须使用一个子类来继承抽象父类
- 子类必须覆盖重写抽象父类当中的所有的抽象方法
- 覆盖重写(实现):子类去掉抽象方法中的abstract关键字,然后补上方法体大括号。
1 package e.e.e; 2 3 public abstract class animail {//抽象方法 4 public abstract void eat();//抽象方法 5 //这是普通方法 6 public void normamethod(){ 7 8 } 9 }
1 package e.e.e; 2 3 public class cat extends animail { 4 @Override 5 public void eat(){ 6 System.out.println("猫吃鱼"); 7 } 8 9 } 10
1 package e.e.e; 2 3 public class demo { 4 public static void main(String[] args) { 5 cat cat = new cat(); 6 cat.eat(); 7 } 8 } 9
4.3注意事项。
- 抽象类不能创建对象,如果创建,编译无法通过而报错,只能创建其非抽象子类的对象,也就是说如果创建类抽象类的对象,调用抽象的方法,而抽象方法没有具体方法体,没有意义
- 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的,也就是说子类的构造方法中,有默认的super()会访问父类的构造方法,进行父类成员初始化。1.抽象父类构造方法先执行,然后子类的构造方法执行,这个父类的构造方法要执行,必须用super()调用。 2.子类即便没有构造方法,那么父类的无参构造方法也会默认执行。
- 抽象类中,不一定包含抽象方法,但有抽象方法的必须是抽象类。未包含抽象方法的抽象类,是不想让调用创建抽象方法的对象,通常用于某种特别结构设计,设计模式中的适配器模式就可以使用这样的。
- 抽象类的子类,必须重写抽象父类所有的抽象方法,否则编译无法通过而报错,除非改子类也是抽象类。
5.案例:
5.3.群主发普通红包
群主发普通红包。某群有多名成员,群主给成员发普通红包。普通红包的规则:
- 1. 群主的一笔金额,从群主余额中扣除,平均分成n等份,让成员领取。
- 2. 成员领取红包后,保存到成员余额中。
请根据描述,完成案例中所有类的定义以及指定类之间的继承关系,并完成发红包的操作
分析:首先有个群,群主是发送红包,群主自己不抢红包,群主金额会减少,成员抢红包,抢到金额进入自己腰包约
1 public class User { 2 private String name;//姓名 3 private int money;// 余额 4 5 public User() {// 无参构造 alt+ insert constructor 啥都不选快速生成 6 } 7 8 public User(String name, int money) {// 有参构造 alt+ insert constructor 全选选快速生成 9 this.name = name; 10 this.money = money; 11 } 12 //展示一下当前用户多少钱 13 public void show(){ 14 System.out.println("我叫:" + name + "我有多少钱" + money); 15 } 16 17 public String getName() { 18 return name; 19 } 20 21 public void setName(String name) { 22 this.name = name; 23 } 24 25 public int getMoney() { 26 return money; 27 } 28 29 public void setMoney(int money) { 30 this.money = money; 31 } 32 } 33
1 import java.util.ArrayList; 2 //群主的类 3 public class Manager extends User{ 4 // 写默认构造和有参构造即可,默认有super(); 5 public Manager(){ 6 7 } 8 9 public Manager(String name, int money) {//叫什么名字、多少钱 10 super(name, money);//参数传递给父类 11 } 12 public ArrayList<Integer> send (int totalMoney,int count){ // 总共要发多少钱,要发几份 13 //首先需要一个集合,存储若干个红包的金额 14 ArrayList<Integer> redList = new ArrayList<>(); 15 // 首先看下群主有多少钱 16 int leftMoney = super.getMoney();//群主当前余额。 17 if(totalMoney > leftMoney){ 18 System.out.println("余额不足"); 19 return redList;// 返回空集合 20 } 21 // 扣钱 就是重新设置余额 22 super.setMoney(leftMoney - totalMoney);// super是父类方法,将余额返回送进父类 23 //发红包需要拆分count分 24 int avg = totalMoney / count; 25 int mod = totalMoney % count; // 余数 也就是取模 26 27 // 除不开的零头放在最后一个红包中 28 // 下面把红包一个一个放在集合中 29 for (int i = 0; i < count - 1; i++) {//最后一个红包单独处理 30 redList.add(avg); 31 } 32 // 最后一个红包 33 int last = avg + mod; 34 redList.add(last); 35 return redList; 36 37 } 38 } 39
1 import java.util.ArrayList; 2 import java.util.Random; 3 4 5 public class Member extends User{ 6 public Member() { 7 } 8 9 public Member(String name, int money) { 10 super(name, money); 11 } 12 public void receive(ArrayList<Integer> list){//红包已经在集合中 13 // 从多个红包当中随便抽泣一个红包,给自己,也就是随机获取集合当中的索引变化。 14 int index = new Random().nextInt(list.size());// random是匿名对象,范围是不能超过集合长度,最高到size-1为止 15 //根据索引,从集合中删除,并且得到被删除的红包,给自己 16 int delta = list.remove(index);//remove返回的是被删除的值,也就是某个抢到的红包钱 17 // 当前成员自己本来多少钱 18 int money = super.getMoney(); 19 //最后成员多少钱,也就是加上后,重新设置回去。 20 super.setMoney(money + delta); 21 22 23 } 24 } 25
1 import java.util.ArrayList; 2 3 public class MainRedPacket { 4 public static void main(String[] args) { 5 Manager manager = new Manager("群主",101); 6 Member member1 = new Member("bingo1",2); 7 Member member2 = new Member("bingo2",2); 8 Member member3 = new Member("bingo3",2); 9 Member member4 = new Member("bingo4",2); 10 manager.show(); 11 member1.show(); 12 member2.show(); 13 member3.show(); 14 member4.show(); 15 // 装群主发红包的集合怎么来的呢 16 ArrayList<Integer> redList = manager.send(20,4); 17 // 四个人去收红包 18 member1.receive(redList); 19 member2.receive(redList); 20 member3.receive(redList); 21 member4.receive(redList); 22 23 manager.show(); 24 member1.show(); 25 member2.show(); 26 member3.show(); 27 member4.show(); 28 } 29 } 30