继承
在继承的关系中,子类就是一个父类,也就是说,子类可以被当做父类看待,例如:父类是员工,子类是程序员,那么程序员就是一个员工,代码示例:
// 员工类 public class Employee{ String name; int age; } // 程序员类(继承员工类) public class Programer extends Employee{ } // 主方法 public class Extends { public static void main(String[] args) { Programer coder = new Programer(); coder.name = "johny"; coder.age = 20; System.out.println(coder.name + " " + coder.age); // johny 20 } }
在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式:
- 直接通过子类对象访问成员变量(优先使用自己的,没有则向上找)
- 间接通过成员方法访问成员变量(看方法属于谁,就优先用谁的,没有则往上找,找不到就报错)
在父子类的继承关系中,创建子类对象,访问成员方法的规则:
- 创建的对象是谁,就优先用谁(优先使用自己的),如果没有就向上找
无论是成员方法还是成员变量,如果没有都是向上找父类,绝不会向下找
区别子类方法中重名的三种变量
局部变量: 直接写成成员变量名
本类中的成员变量:this.成员变量名
父类中的成员变量:super.成员变量名
继承中方法的覆盖
覆盖与方法的重载不同,同样是方法名相同,但覆盖指接收的参数也相同
// 父类 public class Phone { public void call(){ System.out.println("call"); } public void send(){ System.out.println("send"); } } // 子类 public class NewPhone extends Phone{ // 方法权限必须大于等于父类 public void call(){ // 调用父类方法 super.call(); // 添加自己的逻辑 System.out.println("show picture"); } } public class DemoCover { public static void main(String[] args) { NewPhone newPhone = new NewPhone(); newPhone.call(); // call show picture } }
注意事项:
- 在子类方法前面写上 @Override,用来检测是不是有效的覆盖重写
- 子类方法的返回值必须小于等于父类方法的返回值范围(例如:子类返回String,父类返回Object)
- 子类方法的权限必须大于等于父类方法的权限修饰符
权限修饰符:public > protected > (default) > private
继承中构造方法的访问特点
- 子类构造方法中有一个默认隐含的 "super()" 调用,所以一定是先调用的父类构造,再调用的子类构造
- 子类构造可以通过 "super" 关键字来调用父类的重载构造(当父类含有多个构造方法)
- super 的父类构造方法调用,必须是子类构造方法的第一条语句,且只能调用一次 super 构造
子类必须调用父类的构造方法,不写则是默认的 super(),写了就调用指定的 super
super 关键字的三种用法
- 在子类的成员方法中,使用 super 得到父类的成员变量
- 在子类的成员方法中,使用 super 访问父类的成员方法
- 在子类的构造方法中,使用 super 访问父类的构造方法
this 关键字的三种用法
super 关键字用来访问父类内容,而 this 关键字用来访问本类内容
- 在本类的成员方法中,使用 this 得到本类中的成员变量
- 在本类的成员方法中,使用 this 得到本类中的成员方法
- 在本类的构造方法中,使用 this 调用本类的重载构造方法(另一个构造方法)
this(…) 调用也必须是构造方法中的第一条语句,且只能使用一次
super 和 this 两种构造使用,不能同时使用
继承的三个特点图解
抽象方法和抽象类
抽象方法:就是在 void 前面加上 abstract 关键字,然后去掉大括号,直接分号结束
抽象类:抽象方法所在的类,必须是抽象类,但抽象类也可以包含非抽象方法, 在 class 前面加上 abstract 关键字
// 这是一个抽象类 public abstract class Animal{ // 这是一个抽象方法,代表吃东西,具体吃什么?不知道 public abstract void eat(); }
如何使用抽象类和抽象方法?
- 不能直接 new 抽象类,必须使用子类继承抽象父类
- 抽象类中抽象方法和非抽象方法并存
- 非抽象子类必须覆盖重写父类的所有的抽象方法
- 创建非抽象子类对象时进行使用
// 抽象父类 public abstract class Animal{ public Animal(){ System.out.println("抽象父类构造方法执行"); } // 抽象方法 public abstract void eat(); public abstract void sleep(); } // 抽象子类 public abstract class Dog extends Animal{ @Override public void eat(){ System.out.println("dog eat meat"); } } // 间接子类 public class JinMao extends Dog { @Override public void sleep(){ System.out.println("JinMao in his sleeping"); } } public class HaShiQi extends Dog { @Override public void sleep(){ System.out.println("HaShiQi in his sleeping"); } } public class DemoAbstract{ public static void main(String[] args){ JinMao jinMao = new JinMao(); jinMao.eat(); jinMao.sleep(); HaShiQi haShiQi = new HaShiQi(); haShiQi.eat(); haShiQi.sleep(); } } // 执行结果 抽象父类构造方法执行 dog eat meat JinMao in his sleeping 抽象父类构造方法执行 dog eat meat HaShiQi in his sleeping
发红包的案例
User 基类
1 public class User { 2 private String name; 3 private int money; 4 5 // 无参构造 6 public User(){ 7 } 8 // 全参构造 9 public User(String name, int money){ 10 this.name = name; 11 this.money = money; 12 } 13 14 public void setName(String name) { 15 this.name = name; 16 } 17 public void setMoney(int money) { 18 this.money = money; 19 } 20 public String getName() { 21 return name; 22 } 23 public int getMoney() { 24 return money; 25 } 26 27 // show 方法 28 public void show(){ 29 String str = String.format("my name is %s, i have %d yuan", this.name, this.money); 30 System.out.println(str); 31 } 32 }
群主类
1 import java.util.ArrayList; 2 import java.util.Scanner; 3 4 5 public class Manager extends User { 6 public Manager(){}; 7 public Manager(String name, int money){ 8 super(name, money); 9 } 10 11 // 发红包 12 public ArrayList<Integer> send(){ 13 while (true){ 14 // 确定发多少钱,发多少个? 15 Scanner scanner = new Scanner(System.in); 16 int money = scanner.nextInt(); 17 int count = scanner.nextInt(); 18 19 // 发出的红包不得大于群主的总金额 20 if (money > super.getMoney()){ 21 String str = String.format("your balance is %d ! please re-select"); 22 System.out.println(str); 23 continue; 24 } 25 26 // 确定每个红包有多少钱? 27 int avg = money / count; 28 int remainder = money % count; // 余数,就是零头 29 30 // 塞钱进红包 31 ArrayList<Integer> set = new ArrayList<>(); 32 for (int i=0; i<count-1; i++){ 33 set.add(avg); 34 } 35 // 把零头放到最后一个红包 36 set.add(avg + remainder); 37 38 // 减去余额 39 super.setMoney(super.getMoney() - money); 40 return set; 41 } 42 } 43 }
成员类
1 import java.util.ArrayList; 2 import java.util.Random; 3 4 public class Member extends User{ 5 public Member(){}; 6 public Member(String name, int money){ 7 super(name, money); 8 }; 9 10 // 收红包 11 public void receive(ArrayList<Integer> arrayList){ 12 // 随机收取一个红包 13 Random random = new Random(); 14 int index = random.nextInt(arrayList.size()); 15 int cash = arrayList.remove(index); 16 System.out.println(String.format("i got was %d yuan", cash)); 17 // 修改余额 18 super.setMoney(super.getMoney() + cash); 19 } 20 }
主程序
1 import java.util.ArrayList; 2 3 public class MainStart { 4 public static void main(String[] args) { 5 // 拉人建群 6 Manager manager = new Manager("manager", 5000); 7 Member johny = new Member("johny", 10); 8 Member anson = new Member("anson", 0); 9 Member tom = new Member("tom", 0); 10 11 // 发红包 12 ArrayList<Integer> set = manager.send(); 13 // 收红包 14 johny.receive(set); 15 anson.receive(set); 16 tom.receive(set); 17 18 // 活动结束之后都有多少钱? 19 manager.show(); 20 johny.show(); 21 anson.show(); 22 tom.show(); 23 } 24 }
ending ~