第1节 继承
day09_01_继承的概述
day09_02_继承的格式
day09_03_继承中成员变量的访问特点
day09_04_区分子类方法中重名的三种变量
day09_05_继承中成员方法的访问特点
day09_06_继承中方法的覆盖重写_概念与特点
day09_07_继承中方法的覆盖重写_注意事项
day09_08_继承中方法的覆盖重写_应用场景
day09_09_继承中构造方法的访问特点
day09_10_super关键字的三种用法
day09_11_this关键字的三种用法
day09_12_super与this关键字图解
day09_13_Java继承的三个特点
课后练习
第2节 抽象类
day09_14_抽象的概念
day09_15_抽象方法和抽象类的格式
day09_16_抽象方法和抽象类的使用
day09_17_抽象方法和抽象类的注意事项
day09_18_发红包案例_分析
day09_19_发红包案例_实现
课后练习
1 package cn.itcast.day09.demo01; 2 3 /* 4 在继承的关系中,“子类就是一个父类”。也就是说,子类可以被当做父类看待。 5 例如父类是员工,子类是讲师,那么“讲师就是一个员工”。关系:is-a。 6 7 定义父类的格式:(一个普通的类定义) 8 public class 父类名称 { 9 // ... 10 } 11 12 定义子类的格式: 13 public class 子类名称 extends 父类名称 { 14 // ... 15 } 16 */ 17 public class Demo01Extends { 18 19 public static void main(String[] args) { 20 // 创建了一个子类对象 21 Teacher teacher = new Teacher(); 22 // Teacher类当中虽然什么都没写,但是会继承来自父类的method方法。 23 teacher.method(); 24 25 // 创建另一个子类助教的对象 26 Assistant assistant = new Assistant(); 27 assistant.method(); 28 } 29 30 }
1 package cn.itcast.day09.demo01; 2 3 // 定义一个父类:员工 4 public class Employee { 5 6 public void method() { 7 System.out.println("方法执行!"); 8 } 9 10 }
1 package cn.itcast.day09.demo01; 2 3 // 定义了一个员工的子类:讲师 4 public class Teacher extends Employee { 5 }
1 package cn.itcast.day09.demo01; 2 3 // 定义了员工的另一个子类:助教 4 public class Assistant extends Employee { 5 }
1 package cn.itcast.day09.demo02; 2 3 /* 4 在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式: 5 6 直接通过子类对象访问成员变量: 7 等号左边是谁,就优先用谁,没有则向上找。 8 间接通过成员方法访问成员变量: 9 该方法属于谁,就优先用谁,没有则向上找。 10 */ 11 public class Demo01ExtendsField { 12 13 public static void main(String[] args) { 14 Fu fu = new Fu(); // 创建父类对象 15 System.out.println(fu.numFu); // 只能使用父类的东西,没有任何子类内容 16 System.out.println("==========="); 17 18 Zi zi = new Zi(); 19 20 System.out.println(zi.numFu); // 10 21 System.out.println(zi.numZi); // 20 22 System.out.println("==========="); 23 24 // 等号左边是谁,就优先用谁 25 System.out.println(zi.num); // 优先子类,200 26 // System.out.println(zi.abc); // 到处都没有,编译报错! 27 System.out.println("==========="); 28 29 // 这个方法是子类的,优先用子类的,没有再向上找 30 zi.methodZi(); // 200 31 // 这个方法是在父类当中定义的, 32 zi.methodFu(); // 100 33 } 34 35 }
1 package cn.itcast.day09.demo02; 2 3 public class Fu { 4 5 int numFu = 10; 6 7 int num = 100; 8 9 public void methodFu() { 10 // 使用的是本类当中的,不会向下找子类的 11 System.out.println(num); 12 } 13 14 }
package cn.itcast.day09.demo02; public class Zi extends Fu { int numZi = 20; int num = 200; public void methodZi() { // 因为本类当中有num,所以这里用的是本类的num System.out.println(num); } }
1 package cn.itcast.day09.demo03; 2 3 /* 4 局部变量: 直接写成员变量名 5 本类的成员变量: this.成员变量名 6 父类的成员变量: super.成员变量名 7 */ 8 public class Demo01ExtendsField { 9 10 public static void main(String[] args) { 11 Zi zi = new Zi(); 12 13 zi.method(); 14 } 15 16 }
1 package cn.itcast.day09.demo03; 2 3 public class Fu { 4 5 int num = 10; 6 7 }
1 package cn.itcast.day09.demo03; 2 3 public class Zi extends Fu { 4 5 int num = 20; 6 7 public void method() { 8 int num = 30; 9 System.out.println(num); // 30,局部变量 10 System.out.println(this.num); // 20,本类的成员变量 11 System.out.println(super.num); // 10,父类的成员变量 12 } 13 14 }
1 package cn.itcast.day09.demo04; 2 3 /* 4 在父子类的继承关系当中,创建子类对象,访问成员方法的规则: 5 创建的对象是谁,就优先用谁,如果没有则向上找。 6 7 注意事项: 8 无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的。 9 10 重写(Override) 11 概念:在继承关系当中,方法的名称一样,参数列表也一样。 12 13 重写(Override):方法的名称一样,参数列表【也一样】。覆盖、覆写。 14 重载(Overload):方法的名称一样,参数列表【不一样】。 15 16 方法的覆盖重写特点:创建的是子类对象,则优先用子类方法。 17 */ 18 public class Demo01ExtendsMethod { 19 20 public static void main(String[] args) { 21 Zi zi = new Zi(); 22 23 zi.methodFu(); 24 zi.methodZi(); 25 26 // 创建的是new了子类对象,所以优先用子类方法 27 zi.method(); 28 } 29 30 }
1 package cn.itcast.day09.demo04; 2 3 public class Fu { 4 5 public void methodFu() { 6 System.out.println("父类方法执行!"); 7 } 8 9 public void method() { 10 System.out.println("父类重名方法执行!"); 11 } 12 13 }
1 package cn.itcast.day09.demo04; 2 3 public class Zi extends Fu { 4 5 public void methodZi() { 6 System.out.println("子类方法执行!"); 7 } 8 9 public void method() { 10 System.out.println("子类重名方法执行!"); 11 } 12 13 }
1 package cn.itcast.day09.demo05; 2 3 /* 4 方法覆盖重写的注意事项: 5 6 1. 必须保证父子类之间方法的名称相同,参数列表也相同。 7 @Override:写在方法前面,用来检测是不是有效的正确覆盖重写。 8 这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。 9 10 2. 子类方法的返回值必须【小于等于】父类方法的返回值范围。 11 小扩展提示:java.lang.Object类是所有类的公共最高父类(祖宗类),java.lang.String就是Object的子类。 12 13 3. 子类方法的权限必须【大于等于】父类方法的权限修饰符。 14 小扩展提示:public > protected > (default) > private 15 备注:(default)不是关键字default,而是什么都不写,留空。 16 */ 17 public class Demo01Override { 18 19 }
1 package cn.itcast.day09.demo05; 2 3 public class Fu { 4 5 public String method() { 6 return null; 7 } 8 9 }
1 package cn.itcast.day09.demo05; 2 3 public class Zi extends Fu { 4 5 @Override 6 public String method() { 7 return null; 8 } 9 10 }
1 package cn.itcast.day09.demo06; 2 3 public class Demo01Phone { 4 5 public static void main(String[] args) { 6 Phone phone = new Phone(); 7 phone.call(); 8 phone.send(); 9 phone.show(); 10 System.out.println("=========="); 11 12 NewPhone newPhone = new NewPhone(); 13 newPhone.call(); 14 newPhone.send(); 15 newPhone.show(); 16 } 17 18 }
1 package cn.itcast.day09.demo06; 2 3 // 定义一个新手机,使用老手机作为父类 4 public class NewPhone extends Phone { 5 6 @Override 7 public void show() { 8 super.show(); // 把父类的show方法拿过来重复利用 9 // 自己子类再来添加更多内容 10 System.out.println("显示姓名"); 11 System.out.println("显示头像"); 12 } 13 }
1 package cn.itcast.day09.demo06; 2 3 // 本来的老款手机 4 public class Phone { 5 6 public void call() { 7 System.out.println("打电话"); 8 } 9 10 public void send() { 11 System.out.println("发短信"); 12 } 13 14 public void show() { 15 System.out.println("显示号码"); 16 } 17 18 }
1 package cn.itcast.day09.demo07; 2 3 /* 4 继承关系中,父子类构造方法的访问特点: 5 6 1. 子类构造方法当中有一个默认隐含的“super()”调用,所以一定是先调用的父类构造,后执行的子类构造。 7 2. 子类构造可以通过super关键字来调用父类重载构造。 8 3. super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。 9 总结: 10 子类必须调用父类构造方法,不写则赠送super();写了则用写的指定的super调用,super只能有一个,还必须是第一个。 11 */ 12 public class Demo01Constructor { 13 14 public static void main(String[] args) { 15 Zi zi = new Zi(); 16 } 17 18 }
1 package cn.itcast.day09.demo07; 2 3 public class Fu { 4 5 public Fu() { 6 System.out.println("父类无参构造"); 7 } 8 9 public Fu(int num) { 10 System.out.println("父类有参构造!"); 11 } 12 13 }
package cn.itcast.day09.demo07; public class Zi extends Fu { public Zi() { super(); // 在调用父类无参构造方法 // super(20); // 在调用父类重载的构造方法 System.out.println("子类构造方法!"); } public void method() { // super(); // 错误写法!只有子类构造方法,才能调用父类构造方法。 } }
1 package cn.itcast.day09.demo08; 2 3 public class Fu { 4 5 int num = 10; 6 7 public void method() { 8 System.out.println("父类方法"); 9 } 10 11 }
1 package cn.itcast.day09.demo08; 2 3 /* 4 super关键字的用法有三种: 5 1. 在子类的成员方法中,访问父类的成员变量。 6 2. 在子类的成员方法中,访问父类的成员方法。 7 3. 在子类的构造方法中,访问父类的构造方法。 8 */ 9 public class Zi extends Fu { 10 11 int num = 20; 12 13 public Zi() { 14 super(); 15 } 16 17 public void methodZi() { 18 System.out.println(super.num); // 父类中的num 19 } 20 21 public void method() { 22 super.method(); // 访问父类中的method 23 System.out.println("子类方法"); 24 } 25 26 }
1 package cn.itcast.day09.demo09; 2 3 public class Fu { 4 5 int num = 30; 6 7 }
package cn.itcast.day09.demo09; /* super关键字用来访问父类内容,而this关键字用来访问本类内容。用法也有三种: 1. 在本类的成员方法中,访问本类的成员变量。 2. 在本类的成员方法中,访问本类的另一个成员方法。 3. 在本类的构造方法中,访问本类的另一个构造方法。 在第三种用法当中要注意: A. this(...)调用也必须是构造方法的第一个语句,唯一一个。 B. super和this两种构造调用,不能同时使用。 */ public class Zi extends Fu { int num = 20; public Zi() { // super(); // 这一行不再赠送 this(123); // 本类的无参构造,调用本类的有参构造 // this(1, 2); // 错误写法! } public Zi(int n) { this(1, 2); } public Zi(int n, int m) { } public void showNum() { int num = 10; System.out.println(num); // 局部变量 System.out.println(this.num); // 本类中的成员变量 System.out.println(super.num); // 父类中的成员变量 } public void methodA() { System.out.println("AAA"); } public void methodB() { this.methodA(); System.out.println("BBB"); } }
1 package cn.itcast.day09.demo10; 2 3 public class Demo { 4 5 public static void main(String[] args) { 6 Zi zi = new Zi(); 7 8 zi.show(); 9 zi.method(); 10 } 11 12 }
1 package cn.itcast.day09.demo10; 2 3 public class Fu { 4 5 int num = 10; 6 7 public void method() { 8 System.out.println("父类方法"); 9 } 10 11 }
1 package cn.itcast.day09.demo10; 2 3 public class Zi extends Fu { 4 5 int num = 20; 6 7 @Override 8 public void method() { 9 super.method(); // 调用了父类方法 10 System.out.println("子类方法"); 11 } 12 13 public void show() { 14 int num = 30; 15 System.out.println(num); // 30 16 System.out.println(this.num); // 20 17 System.out.println(super.num); // 10 18 } 19 20 }
1 package cn.itcast.day09.demo11; 2 3 public class DemoMain { 4 5 public static void main(String[] args) { 6 // Animal animal = new Animal(); // 错误写法!不能直接创建抽象类对象 7 8 Cat cat = new Cat(); 9 cat.eat(); 10 } 11 12 }
1 package cn.itcast.day09.demo11; 2 3 /* 4 抽象方法:就是加上abstract关键字,然后去掉大括号,直接分号结束。 5 抽象类:抽象方法所在的类,必须是抽象类才行。在class之前写上abstract即可。 6 7 如何使用抽象类和抽象方法: 8 1. 不能直接创建new抽象类对象。 9 2. 必须用一个子类来继承抽象父类。 10 3. 子类必须覆盖重写抽象父类当中所有的抽象方法。 11 覆盖重写(实现):子类去掉抽象方法的abstract关键字,然后补上方法体大括号。 12 4. 创建子类对象进行使用。 13 */ 14 public abstract class Animal { 15 16 // 这是一个抽象方法,代表吃东西,但是具体吃什么(大括号的内容)不确定。 17 public abstract void eat(); 18 19 // 这是普通的成员方法 20 // public void normalMethod() { 21 // 22 // } 23 24 }
1 package cn.itcast.day09.demo11; 2 3 public class Cat extends Animal { 4 5 @Override 6 public void eat() { 7 System.out.println("猫吃鱼"); 8 } 9 10 }
1 package cn.itcast.day09.demo12; 2 3 public class DemoMain { 4 5 public static void main(String[] args) { 6 Zi zi = new Zi(); 7 zi.eat(); 8 } 9 10 }
1 package cn.itcast.day09.demo12; 2 3 public abstract class Fu { 4 5 public Fu() { 6 System.out.println("抽象父类构造方法执行!"); 7 } 8 9 public abstract void eat(); 10 11 }
1 package cn.itcast.day09.demo12; 2 3 public class Zi extends Fu { 4 5 public Zi() { 6 // super(); 7 System.out.println("子类构造方法执行"); 8 } 9 10 @Override 11 public void eat() { 12 System.out.println("吃饭饭"); 13 } 14 }
1 package cn.itcast.day09.demo12; 2 3 /* 4 一个抽象类不一定含有抽象方法, 5 只要保证抽象方法所在的类是抽象类,即可。 6 7 这样没有抽象方法的抽象类,也不能直接创建对象,在一些特殊场景下有用途。 8 */ 9 public abstract class MyAbstract { 10 }
1 package cn.itcast.day09.demo13; 2 3 public class DemoMain { 4 5 public static void main(String[] args) { 6 // Animal animal = new Animal(); // 错误! 7 8 // Dog dog = new Dog(); // 错误,这也是抽象类 9 10 Dog2Ha ha = new Dog2Ha(); // 这是普通类,可以直接new对象。 11 ha.eat(); 12 ha.sleep(); 13 System.out.println("=========="); 14 15 DogGolden golden = new DogGolden(); 16 golden.eat(); 17 golden.sleep(); 18 } 19 20 21 }
1 package cn.itcast.day09.demo13; 2 3 // 最高的抽象父类 4 public abstract class Animal { 5 6 public abstract void eat(); 7 8 public abstract void sleep(); 9 10 }
1 package cn.itcast.day09.demo13; 2 3 // 子类也是一个抽象类 4 public abstract class Dog extends Animal { 5 6 @Override 7 public void eat() { 8 System.out.println("狗吃骨头"); 9 } 10 11 // public abstract void sleep(); 12 }
1 package cn.itcast.day09.demo13; 2 3 public class Dog2Ha extends Dog { 4 @Override 5 public void sleep() { 6 System.out.println("嘿嘿嘿……"); 7 } 8 }
1 package cn.itcast.day09.demo13; 2 3 public class DogGolden extends Dog { 4 @Override 5 public void sleep() { 6 System.out.println("呼呼呼……"); 7 } 8 }
1 package cn.itcast.day09.demo14; 2 3 import java.util.ArrayList; 4 5 public class MainRedPacket { 6 7 public static void main(String[] args) { 8 Manager manager = new Manager("群主", 100); 9 10 Member one = new Member("成员A", 0); 11 Member two = new Member("成员B", 0); 12 Member three = new Member("成员C", 0); 13 14 manager.show(); // 100 15 one.show(); // 0 16 two.show(); // 0 17 three.show(); // 0 18 System.out.println("==============="); 19 20 // 群主总共发20块钱,分成3个红包 21 ArrayList<Integer> redList = manager.send(20, 3); 22 // 三个普通成员收红包 23 one.receive(redList); 24 two.receive(redList); 25 three.receive(redList); 26 27 manager.show(); // 100-20=80 28 // 6、6、8,随机分给三个人 29 one.show(); 30 two.show(); 31 three.show(); 32 } 33 34 }
1 package cn.itcast.day09.demo14; 2 3 import java.util.ArrayList; 4 5 // 群主的类 6 public class Manager extends User { 7 8 public Manager() { 9 } 10 11 public Manager(String name, int money) { 12 super(name, money); 13 } 14 15 public ArrayList<Integer> send(int totalMoney, int count) { 16 // 首先需要一个集合,用来存储若干个红包的金额 17 ArrayList<Integer> redList = new ArrayList<>(); 18 19 // 首先看一下群主自己有多少钱 20 int leftMoney = super.getMoney(); // 群主当前余额 21 if (totalMoney > leftMoney) { 22 System.out.println("余额不足"); 23 return redList; // 返回空集合 24 } 25 26 // 扣钱,其实就是重新设置余额 27 super.setMoney(leftMoney - totalMoney); 28 29 // 发红包需要平均拆分成为count份 30 int avg = totalMoney / count; 31 int mod = totalMoney % count; // 余数,也就是甩下的零头 32 33 // 除不开的零头,包在最后一个红包当中 34 // 下面把红包一个一个放到集合当中 35 for (int i = 0; i < count - 1; i++) { 36 redList.add(avg); 37 } 38 39 // 最后一个红包 40 int last = avg + mod; 41 redList.add(last); 42 43 return redList; 44 } 45 }
1 package cn.itcast.day09.demo14; 2 3 import java.util.ArrayList; 4 import java.util.Random; 5 6 // 普通成员 7 public class Member extends User { 8 9 public Member() { 10 } 11 12 public Member(String name, int money) { 13 super(name, money); 14 } 15 16 public void receive(ArrayList<Integer> list) { 17 // 从多个红包当中随便抽取一个,给我自己。 18 // 随机获取一个集合当中的索引编号 19 int index = new Random().nextInt(list.size()); 20 // 根据索引,从集合当中删除,并且得到被删除的红包,给我自己 21 int delta = list.remove(index); 22 // 当前成员自己本来有多少钱: 23 int money = super.getMoney(); 24 // 加法,并且重新设置回去 25 super.setMoney(money + delta); 26 } 27 }
1 package cn.itcast.day09.demo14; 2 3 public class User { 4 5 private String name; // 姓名 6 private int money; // 余额,也就是当前用户拥有的钱数 7 8 public User() { 9 } 10 11 public User(String name, int money) { 12 this.name = name; 13 this.money = money; 14 } 15 16 // 展示一下当前用户有多少钱 17 public void show() { 18 System.out.println("我叫:" + name + ",我有多少钱:" + money); 19 } 20 21 public String getName() { 22 return name; 23 } 24 25 public void setName(String name) { 26 this.name = name; 27 } 28 29 public int getMoney() { 30 return money; 31 } 32 33 public void setMoney(int money) { 34 this.money = money; 35 } 36 }