网站建设课程学习,windows最新一代,一个好的网站建设需要多少钱,推广恶意点击软件怎样使用8.继承与多态 8.2 多态8.2.1 多态的概念8.2.2 多态实现条件8.2.3 重写8.2.4 向上转型和向下转型8.2.5 向下转型8.2.6 多态的优缺点8.2.7 避免在构造方法中调用重写的方法 8.2 多态
8.2.1 多态的概念
通俗来说就是多种形态#xff0c;具体点就是去完成某个行为#xff0c;当… 8.继承与多态 8.2 多态8.2.1 多态的概念8.2.2 多态实现条件8.2.3 重写8.2.4 向上转型和向下转型8.2.5 向下转型8.2.6 多态的优缺点8.2.7 避免在构造方法中调用重写的方法 8.2 多态
8.2.1 多态的概念
通俗来说就是多种形态具体点就是去完成某个行为当不同的对象去完成时会产生出不同的状态。 就比如打印机彩色打印机和黑白打印机打印出的效果一个是彩色一个是黑白。
即同一件事情发生在不同对象身上就会产生不同的结果。
8.2.2 多态实现条件
在Java中要实现多态必须要满足以下条件
必须在继承体系下子类必须要对父类方法进行重写通过父类的引用调用重写的方法
多态的体现在代码运行时当传递不同类对象时会调用对应类中的方法。
8.2.3 重写
重写(override)也称为覆盖。重写是子类对父类非静态、非private修饰非final修饰非构造方法等的实现过程进行重新编写, **返回值和形参都不能改变。即外壳不变核心重写**重写的好处在于子类可以根据需要定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。 重写的规则
方法名一样参数列表相同个数、数据类型、顺序返回值一样
注意: 不能被重写的4种情况
被final修饰的方法 不可以被重写。这个方法叫做密封方法。 public final void eat() {System.out.println(this.name 正在吃。。。);}被static修饰的方法 不能被重写
public static void eat() {System.out.println(this.name 正在吃。。。);}子类重写父类方法的时候子类的方法访问修饰限定符要父类
// 父类的方法
//当父类的方法修饰限定符是 默认defau时子类的方法访问修饰限定符可以是protected、public
public void eat() {System.out.println(this.name 正在吃。。。);}//子类的方法
public void eat() {System.out.println(this.name 正在吃狗粮...);}被private修饰的方法 是不被重写的
重写和重载的区别 重写的方法名和参数都一样而重载的方法名相同参数不同。 即方法重载是一个类的多态性表现而方法重写是子类与父类的一种多态性表现。
通过反汇编代码
动态绑定子类和父类都有 编译得时候认为 还是确认调用了父类得eat方法 运行得时候 绑定到子类当中
父类引用 引用 子类对象通过父类引用 去调用 父类 和子类 同名的方法。
静态绑定编译的时候就已经确定调用哪个方法了如下dog.barks(10)
8.2.4 向上转型和向下转型
向上转型实际就是创建一个子类对象将其当成父类对象来使用。 语法格式父类类型 对象名 new 子类类型()
直接赋值
Animal animal new Dog(旺财,10,红色); //直接赋值方法传参 // 方法传参 形参作为父类引用可以接受任意子类的对象public static void fun(Animal animal) {animal.eat();// 发生了多态}public static void main(String[] args) {Dog dog new Dog(旺财,3,红色);fun(dog);Bird bird new Bird(布谷,1);fun(bird);}同一个引用 调用了 同一个方法当是因为引用的对象不一样所表现的行为不一样称为多态。
方法返回 // 通过返回值进行向上转型public static Animal fun2() {return new Dog(旺财,3,红色);}向下转型能让代码变得更加简单灵活缺点就是不能调用到子类特有的方法。
8.2.5 向下转型
Java中为了提高向下转型的安全性引入了instanceof 如果该表达式为true则可以安全转换。 public static void main(String[] args) {Animal animal2 new Bird(布谷,1);//animal2.eat();//animal2.fly();Bird bird (Bird) animal2;bird.fly();Animal animal1 new Dog(旺财,3,红色);if (animal1 instanceof Bird) {Bird bird2 (Bird) animal1;bird2.fly();}else {System.out.println(不一定所以的动物都是鸟);}}8.2.6 多态的优缺点
使用多态的好处
能够降低代码的圈复杂度避免使用大量的if-else 用if-else
class Shape {public void draw() {System.out.println(画图形);}
}
class Cycle extends Shape {Overridepublic void draw() {System.out.println(⚪);}
}
class Rect extends Shape {Overridepublic void draw() {System.out.println(矩形);}
}class Triangle extends Shape {Overridepublic void draw() {System.out.println(三角形);}
}
public class Test {public static void main(String[] args) {Rect rect new Rect();Cycle cycle new Cycle();Triangle triangle new Triangle();String[] shapes {cycle, rect, cycle, rect, triangle};for (String shape : shapes) {if (shape.equals(cycle)) {cycle.draw();} else if (shape.equals(rect)) {rect.draw();} else if (shape.equals(triangle)) {triangle.draw();}}}}用多态
class Shape {public void draw() {System.out.println(画图形);}
}
class Cycle extends Shape {Overridepublic void draw() {System.out.println(⚪);}
}
class Rect extends Shape {Overridepublic void draw() {System.out.println(矩形);}
}class Triangle extends Shape {Overridepublic void draw() {System.out.println(三角形);}
}
public class Test {// 使用多态public static void main(String[] args) {Rect rect new Rect();Cycle cycle new Cycle();Triangle triangle new Triangle();// 向上转型Shape[] shapes {cycle,rect,cycle,rect,triangle};for (Shape shape : shapes) {shape.draw();}}
}可扩展能力更强 如果需要新加一种形状使用多态的方式代码改动成本也比较低 比如新加一个画❀
class Flower extends Shape {Overridepublic void draw() {System.out.println(❀);}
}
public class Test {public static void main(String[] args) {Rect rect new Rect(); // 相当于Shape rect new Rect();Cycle cycle new Cycle();Triangle triangle new Triangle();Flower flower new Flower();// 向上转型Shape[] shapes {cycle,rect,cycle,rect,triangle,flower};for (Shape shape : shapes) {shape.draw();}}
}缺点 代码的运行效率降低
属性没有多态性 当父类和子类都有同名属性的时候通过父类引用只能引用父类自己的成员属性构造方法没有多态性
8.2.7 避免在构造方法中调用重写的方法
当在父类的构造方法当中调用父类和子类同名的方法时候此时也会发生动态绑定。也意味着 构造方法内 也会发生动态绑定。 注意 在构造方法当中 不要调用重写的方法。
class B {public B() {// 父类的实例 -- 父类的构造 -- 子类的实例 -- 子类的构造func(); // 调用子类的func方法 没有给num赋值 所以num的值为0}public void func() {System.out.println(B.func());}
}
class D extends B {private int num 1;public D() {super();}Overridepublic void func() {System.out.println(D.func() num);}
}
public class Test2 {public static void main(String[] args) {//1. 分配内存空间 2. 调用合适的构造方法D d new D();}
}构造 D 对象的同时, 会调用 B 的构造方法.B 的构造方法中调用了 func 方法, 此时会触发动态绑定, 会调用到 D 中的 func此时 D 对象自身还没有构造, 此时 num 处在未初始化的状态, 值为 0.。所以在构造函数内尽量避免使用实例方法除了final和private方法。
结论用尽量简单的方式使对象进入可工作状态尽量不要在构造器中调用方法如果这个方法被子类重写就会触发动态绑定但是此时子类对象还没构造完成可能会出现一些隐藏的但是又极难发现的问题。