继承和多态
目录:
承接上回
1.9proteced关键字🛰
1.10继承方式🛰
- 单继承
class A{
}
class B extends A{
}
- 多层继承
class A{
}
class B extends A{
}
class C extends B{
}
- 不同类继承同一个类
class A{
}
class B extends A{
}
class C extends A{
}
1.11final关键字🛰
-
final int Size = 10 //常量;
-
final class B extend A {}
//密封类:表示此类不能再被继承 -
final修饰方法//密封方法:代表此方法不能被重写
1.12继承与组合🛰
-
继承是is - a的关系
- 比如说狗是动物
-
组合是has a or a part of
-
比如说学校由学生和老师组成
-
class Student{ } class Teacher{ } class School{ private Student[] students; private Teacher[] teachers; }
-
2.多态😋
2.1多态的概念🛰
多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同 的状态。
2.2多态的条件🛰
-
完成向上转型
-
直接赋值
Animal animal = new Bird("鹦鹉",2);
-
方法的传参
public static void func1(Animal animal){ } public static void main(String[] args) { Bird bird = new Bird("鹦鹉",2); func1(bird); }
-
方法的返回值
public static Animal func2(){ return new Bird("鹦鹉",2); }
-
-
完成方法的重写
-
通过父类的引用来调用这个重写的方法(动态绑定)
2.3重写🛰
-
满足方法重写的条件
- 方法名相同
- 方法的参数列表相同【个数,类型,顺序】
- 方法的返回值相同
- 协变类型:子类的返回值与父类的返回值是父子关系也可以
- static修饰的方法不能被重写
- private修饰的方法不能被重写
- 子类的访问修饰符要大于等于父类的访问修饰符
-
重写与重载的区别
类型 重载 重写 参数列表 必须修改 一定不能修改 返回值类型 可以修改 一定不能修改 访问限定修饰符 可以修改 一定不能做更严格的限制 -
动态绑定
-
class Animal{ private String name; private int age; public Animal(String name, int age) { this.name = name; this.age = age; //eat();->也可以发生所谓的动态绑定,以后不要这样写代码 } } class Bird extends Animal{ public String wing; public Bird(String name, int age) { super(name, age); } public void fly(){ System.out.println(getName()+" 正在飞"); } @Override public void eat() { System.out.println(getName()+" 要吃鸟粮"); } } public static void main(String[] args) { // Bird bird = new Bird("小鸟",3); // Animal animal = bird; //父类的引用 引用了子类的对象 Animal animal = new Bird("鹦鹉",2); animal.eat();//动态绑定 会输出子类的eat // animal.fly();//不可以调用了 此时通过父类引用,只能调用自己特有的方法,不可以调用子类方法 // animal.wing; }
-
静态绑定:例如方法的重载
2.4向上转型和向下转型🛰
2.4.1向上转型
在多态的条件中已经介绍
2.4.2向下转型
**向下转型非常不安全,不用 **
public static void main(String[] args) {
Animal animal = new Dog("狗子",3);
if(animal instanceof Bird){
//不是所有的动物都是鸟
Bird bird = (Bird)animal;
bird.fly();
}
}
public static void main5(String[] args) {
Animal animal = new Bird("鸟儿",3);
Bird bird = (Bird)animal;//向下转型
bird.fly();
}
2.5多态的优缺点🛰
【使用多态的好处】
- 能够降低代码的 “圈复杂度”, 避免使用大量的 if - else
- 可扩展能力更强
- 如果要新增一种新的形状, 使用多态的方式代码改动成本也比较低.
public static void drawMap3(){
Rect rect = new Rect();
Cycle cycle = new Cycle();
Flower flower = new Flower();
Shape[] shapes = {cycle, rect, cycle, rect, flower};
for (Shape shape:shapes) {
shape.draw();
}
}
public static void drawMap2(){
Rect rect = new Rect();
Cycle cycle = new Cycle();
Flower flower = new Flower();
String[] shapes = {"cycle", "rect", "cycle", "rect", "flower"};
for (String shape : shapes) {
if (shape.equals("cycle")) {
cycle.draw();
} else if (shape.equals("rect")) {
rect.draw();
} else if (shape.equals("flower")) {
flower.draw();
}
}
}
public static void main(String[] args) {
drawMap3();
}
【多态的缺陷】
代码的运行效率降低。
2.6尽量避免在构造方法中重写🛰
public Animal(String name, int age) {
this.name = name;
this.age = age;
//eat();->也可以发生所谓的动态绑定,以后不要这样写代码
}
class Bird extends Animal{
public String wing;
public Bird(String name, int age) {
super(name, age);
}
public void fly(){
System.out.println(getName()+" 正在飞");
}
@Override
public void eat() {
System.out.println(getName()+" 要吃鸟粮");
}
}
public class Test {
public static void main(String[] args) {
Animal animal = new Animal("动物",10);
// Animal animal = new Dog("狗子",3);
animal.eat();
}
}
结论: “用尽量简单的方式使对象进入可工作状态”, 尽量不要在构造器中调用方法(如果这个方法被子类重写, 就会触发动态绑定, 但是此时子类对象还没构造完成), 可能会出现一些隐藏的但是又极难发现的问题.