继承
- 认识继承
继承是指,如果有两个类,有很多的重复的代码,那么就可以把重复的写到A上面,然后B继承A,这样B就不需要再写重复代码了。
-
权限修饰符
一般来说,成员变量都是private修饰,方法都是public修饰,其他两个很少用到。
缺省就是什么都没有
-
继承的特点
1.单继承:一个类只能继承一个直接父类
2.多层继承:也可以有爷爷类
3.祖宗类:所有类都是object类的子类
4.就近原则:优先访问自己类的,自己类没有的才访问父类
例如这个代码,因为就近原则,第一个输出的name就是show的name;第二个用了this.name是因为成员变量和局部变量相同了,所以加了this;第三个super的用法是指定访问父类的方法或变量
小结
- 方法重写
方法重写就是子类跟父类有相似的功能,但是又有细小的区别,那就在子类里重写写一个同名的方法,把父类的覆盖掉。
注意,再重写的方法上面最好加上@overried,作为方法重写的注解。
小结
访问权限就是上面的修饰符权限
常见的应用场景是:因为所有的类都是object的子类,当一个类想要直接输出对象数据时,就需要修该object类 的方法
可以直接右键自动生成
这样,在输出对象的时候,就会输出对象的数据,而不是对象的地址
- 子类构造器的特点
子类的所有构造器,都会先调用父类的构造器,再执行自己
new的时候就会访问Zi的无参构造器,但是Zi就会先访问Fu的构造器,再访问自己的。
package com.itheima.extends6constructor;
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
//认识子类构造器的特点,在看应用场景
//子类构造器必须先调用父类构造器,再执行自己构造器
//为什么一定要先super()调用父类构造器呢,是因为赋值的时候,子类里实际上并没有父类属性,所以需要先调用父类构造器,把值赋给父类的公共元素,再把子类单独有的进行赋值
}
}
class Zi extends Fu{
public Zi(){
//super();//默认存在的写不写都有,作用是调用父类的无参构造器
//super(66);//指定调用父类有参构造器
System.out.println("子类无参构造器构造器执行了");
}
}
class Fu{
public Fu(){
System.out.println("父类无参构造器构造器执行了");
}
public Fu(int a){
System.out.println("父类有参构造器构造器执行了");
}
}
super的作用如图,子类里独有的属性,可以直接赋值,父类的属性,就通过super调用父类的有参构造器进行赋值。
小结
6.构造器用this调用兄弟构造器
指的是假设有两个有参构造器,一个接收1,2,3,一个接收1,2,3,4;其中1,2,3都是重复的,那么就可以用this直接调用下面的,进行赋值,代码如下演示:
package com.itheima.extends6constructor;
public class Test2 {
public static void main(String[] args) {
//理解this()调用兄弟构造器
//创建对象,存储一个学生数据
Student s1 = new Student("小王", 18, '男');
System.out.println(s1);
System.out.println("==================");
Student s2 = new Student("小秦", 22, '男');
System.out.println(s2);
}
}
这是两个不同的对象
然后在类里面存储数据
package com.itheima.extends6constructor;
public class Student {
private String name;
private int age;
private char sex;
private String schoolName;
public Student() {
}
public Student(String name, int age, char sex) {
// this.name = name;
// this.age = age;
// this.sex = sex;
// this.schoolName = "传智播客";
//this调用兄弟构造器
//注意事项:super()、this()必须写到构造器的第一行,且两者不能同时出现
this(name,age,sex,"传智播客");//这一行代码跟上面四行代码等价
}
public Student(String name, int age, char sex, String schoolName) {
this.name = name;
this.age = age;
this.sex = sex;
this.schoolName = schoolName;
}
模板实际有四个数据,而我只输入了三个,应该调用第一个构造器,但是第一个构造器跟第二个构造器又差不多,所有直接把第一个构造器 用this来调用下一个进行了,节省代码;
且this和super都要写到第一排,并且不能同时出现(因为this默认有一个super了)
小结
多态
- 认识多态
多态指的是:父类引用指向子类对象,然后调用方法时,会根据实际对象去执行对应的方法。
比如
class Animal {
public void makeSound() {
System.out.println("动物叫");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("汪汪汪");
}
}
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("喵喵喵");
}
}
父类都是动物叫,但是不同的动物叫声是不同的
使用多态
public class Test {
public static void main(String[] args) {
Animal a1 = new Dog(); // 父类引用指向子类对象
Animal a2 = new Cat();
a1.makeSound(); // 输出:汪汪汪
a2.makeSound(); // 输出:喵喵喵
}
}
用父类的应用数据指向子类对象,用来区分不同的动物叫,然后输出不同的数据。
对象多态就是上面的解释;
行为多态是指,执行同样的方法,会因为对象多态,而执行相应的子类重写的方法。
注意编译看左边,运行看右边:编译的时候也许不会报错,但是运行的时候可能报错:比如animal有makesound,但是某个子类没有makesound,那么编译的时候不会报错,但是执行的时候会因为缺失方法而报错
- 多态的好处
多态的好处1:可以解耦合,可以在不修改大量代码的情况下,随意更换子对象
多态的好处2:父类类型的变量作为参数,可以直接接收一个子类对象,自动识别
package com.itheima.polymorphsm2;
public class Test {
public static void main(String[] args) {
//认识多态的代码
//多态的好处1:右边对象是解耦合的
Animal a1 = new Tortoise();
a1.run();
//多态好处2:父类类型的变量作为参数,可以直接接收一个子类对象
Wolf w = new Wolf();
go(w);
}
//宠物游戏:所有动物都可以送给这个方法开始跑步
public static void go(Wolf w){//这里只能接收Wolf类型的参数,但是改成Animal的话,就可以接收所有数据类型了
System.out.println("开始");
w.run();
}
}
多态的问题:多态下不能使用子类的独有功能,只能使用跟父类同名的重写的方法
- 多态下的类型转化
强制类型转换,比如animal类型的对象想要执行子类的方法,直接使用肯定会报错,那就将animal转换为子类对象的类型,就可以使用子类独有的功能了
Tortoise t1 = (Tortoise) a1;
t1.run();
还有一个问题
也就是说像上一段代码,a1本来就是披着animal外皮的tor,真实类型就是tor,与强转后的类型是相同的,所以不会报错,但是要是不同的话就会报错
所以需要先判断
代码比如
if (a1 instanceof Wolf){
Wolf w2 = (Wolf) a1;
w2.run();
}else if (a1 instanceof Tortoise){
Tortoise t2 = (Tortoise) a1;
t2.run();
}
ins相当于一个等号,如果相等,就直接抢强制转换,否则就转换成另一个对象,反正一共就两个
小结
实际案例
代码如下:
测试类:
package com.itheima.demo;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
//加油站支付小程序
//1.创建卡片类,以便创建金卡或者银卡对象,封装车主的数据
//2.定义一个卡片:card父类,定义金卡和银卡的共同属性和方法
//3.创建一个金卡对象,继承card类,金卡需要重写消费方法(8折优惠)
GoldCard gc = new GoldCard("川54474", "小秦","123456789",5000 );
pay(gc);
//4.创建一个银卡对象,继承card类,银卡需要重写消费方法(9折优惠)
SIlverCard sc = new SIlverCard("川456474", "小川","123456789",5000 );
pay(sc);
//5.创建一个金卡对象,交给一个独立业务(支付机):存款、消费
//6.创建一个银卡对象,交给一个独立业务(支付机):存款、消费
}
//支付机:用一个方法来刷卡:可能接收金卡,也可能接收银卡
public static void pay(Card c){
System.out.println("请刷卡,请您输入当前消费的金额:");
Scanner sc = new Scanner(System.in);
double money = sc.nextDouble();
c.consume(money);
}
}
这里是创建了两张不同的卡,然后数据赋值,下面再输入消费多少进行计算,这里方法的Card c用到了对象多态,自动识别金卡银卡
卡片模板:
package com.itheima.demo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data//lombok可以实现为类自动添加getter和setter方法,无参构造器、toString方法
@NoArgsConstructor//添加一个无参构造器
@AllArgsConstructor//添加一个所有参数的有参构造器
public class Card {
private String cardId;//车牌号
private String name;
private String phone;
private double money;//余额
//预存金额
public void deposit (double money){
this.money += money;
}
//消费金额
public void consume (double money){
this.money -= money;
}
}
卡片模板还包含了两个公共的方法,存钱不管金卡银卡都一样,而消费的计算是不一样的,所以需要重写方法,方法多态。
金卡:
package com.itheima.demo;
public class GoldCard extends Card{
public GoldCard(String cardId, String name, String phone, double money) {
super(cardId,name,phone,money);
}
@Override
public void consume(double money) {
System.out.println("您当前金卡消费:"+money);
System.out.println("优惠后的价格:"+money*0.8);
if (getMoney()<money*0.8){
System.out.println("您的余额不足,请充值");
return;//干掉方法,直接返回
}
//更新金卡的账户余额
setMoney(getMoney()-money*0.8);
//判断消费大于200,调用一个独有功能,打印洗车票
if(money*0.8>200){
printTicket();
}
}
public void printTicket(){
System.out.println("恭喜您,获得一张洗车票");
}
}
首先金卡接收数据,然后用super将数据传给模板,然后将double money传给方法输出消费的金额,这里需要进行一个判断,getMoney就是余额,然后再更新余额
银卡:
package com.itheima.demo;
public class SIlverCard extends Card{
public SIlverCard(String cardId, String name, String phone, double money) {
super(cardId,name,phone,money);
}
@Override
public void consume(double money) {
System.out.println("您当前银卡消费:" + money);
System.out.println("优惠后的价格:" + money * 0.9);
if (getMoney()<money*0.9){
System.out.println("您的余额不足,请充值");
return;//干掉方法,直接返回
}
//更新银卡的账户余额
setMoney(getMoney() - money * 0.9);
}
}
跟金卡同理
对象多态是“一个引用能指向多种对象”, 方法多态是“一个方法名在不同对象中有不同行为”。 它们共同构成了 Java 中多态的核心能力。