回顾
继承:对共性的抽取,实现对代码的复用。
is a 的关系 例如:Dog is an Animal;
this super 构造方法的使用
面向对象三大特性:封装 继承 多态
多态
去完成某个行为,不同的对象会产生不同的结果
同一件事情,发生在不同对象身上,就会产生不同的结果。
多态实现的条件
必须存在:向上转型(把子类对象给父类) ,重写,继承
1.必须在继承体系下
2.子类必须要对父类中的方法进行重写
3.通过父类的引用调用重写的方法
例:
向上转型
向上转型1(直接赋值)
建立在继承关系上
问题:为什么无法访问这个方法?
答:当我们发生向上转型时,只能通过父类的引用访问父类特有的方法,无法访问子类的特性
向上转型2(方法的传参)
向上转型3(方法的返回值)
重写(override) | 重载
1.方法名称相同
2.方法所含参数相同 |(不同)
3.方法返回值相同
例:
引入:@Override(重写的注解)这个注解的意思是当前代码是被重写的,如果有问题则报错
重写正常则不报错
也可通过编译器自动生成
动态绑定
1.向上转型
优点:使代码更加灵活
缺点:不能够访问到子类中特有的属性/方法
2.重写
3.通过父类的调用访问子类当中和父类同名的方法
通过查看字节码文件发现,确实和我们猜测一样,调用父类的eat()方法
编译时与运行时不一样(可以理解为运行时候帮我们调用了重写)多态的基础
提问:有没有静态绑定?
例如:重载1.方法名相同2.返回值相同3.包含参数不同
在编译的时候我已经知道了应该调用哪个方法
重写需要注意的点
1.当父类中的方法被private修饰时是无法进行重写的
2.static 修饰的方法是不能重写的(静态方法)
3.子类的修饰权限要大于或者等于父类的修饰权限
权限大小:private<默认权限/包访问权限<protected<public
4.当父类中的方法被final修饰时是无法进行重写的(此时这个方法被称为密封方法)
5.父类构造方法不可以重写
重写和重载的区别
多态
对于方法中的Animal 参数 他不知自己将来会调用那个对象
但我们知道:当调用哪个对象的时候就会调用它相对应的eat方法
从而知道 当父类引用引用的对象不一样的时候,表现出来的行为也是不一样的
我们就把他叫做多态!!!
多态优缺点的感受:
优点:
1.降低代码的圈复杂度(一般不超过10),避免使用大量的if --else
2.可扩展能力强 如果需要新的东西 加就好了再定义一个新的类的实力
缺陷:代码运行效率降低
1.属性没有多态性
2.构造方法没有多态性
例:画图形
class Shape {
public void draw() {
System.out.println("画图形!");
}
}
class Rect extends Shape {
@Override
public void draw() {
System.out.println("画矩形!");
}
}
class Cycle extends Shape {
@Override
public void draw() {
System.out.println("画圆形! ");
}
}
class Flower extends Shape {
@Override
public void draw() {
System.out.println("❀!");
}
}
public class Test3 {
public static void drawMap(Shape sh1) {
sh1.draw();
}
public static void main(String[] args) {
Shape shape1 = new Rect();
drawMap(shape1);
System.out.println("==============");
Shape shape2 = new Cycle();
drawMap(shape2);
System.out.println("==============");
drawMap(new Flower());
}
}
注意:当在父类的构造方法中调用父类与子类重写的方法,会执行子类的方法!!!
例:
class B {
public B() {
func();// 以后不要这样写 !!
}
public void func() {
System.out.println("B.func()");
}
}
class D extends B {
private int num = 1;
public D() {
super();
}
@Override
public void func() {
//System.out.println("fafdadssa!!!!!");
System.out.println("D.func() " + num + " 因为父类此时还没有走完!");
}
}
public class Test4 {
public static void main(String[] args) {
D d = new D();
}
}
向下转型:
向下转型非常不安全
可以通过if语句和instanceof关键字来判断是否满足需要
抽象类
面向对象的概念中,所有的对象都是用类来描绘的,但是反过来,并不是所有类都是用来描述对象的,如果一个类中没有足够的信息来描绘一个对象,就叫做抽象类。
问题:抽象类和普通类有什么区别?
1.抽象类不能实例化 普通类可以
2.抽象类当中可以包含非抽象方法和抽象方法,但普通类只能包含非抽象方法
3.抽象类也是类可以包含普通成员变量/方法/构造方法
抽象类的特性
1.通过abstract 关键字来修饰类
2.抽象类不能被实例化
3.此时在抽象类当中可以有抽象方法或者非抽象方法
4.什么是抽象方法(一个方法被abstract修饰,没有具体内容,只要包含抽象方法,那么这个类一定是抽象类)
5.当一个普通类继承了抽象类,那么必须重写抽象类中的抽象方法,否则会编译报错
6.抽象类就是用来被继承的,也可以有自己的成员变量,成员方法,与其它类一样
7.抽象方法不能被private ,final,static修饰
8.当一个子类没有重写抽象的父类的方法,可以把当前子类变为abstra修饰
9.当这个类再被继承时,一定要去重写抽象方法,否则子类也是抽象类,继续用abstract修饰
10.抽象类当中不一定包含抽象方法
11.抽象类可以有构造方法,供子类在创建对象时,先初始化父类的对象。
抽象类的作用:
本身不能被实例化,只能创建出该抽象类的子类,然后让子类去重写出抽象类的抽象方法。相当于多了一重编译器的检验,其次实际工作由子类完成。当不小心用成父类了,普通编译器是不会报错的,但抽象类在实例化对象时会报错,帮助我们尽快发现问题。