一、多态的理解:
去完成某个行为,当不同的对象去完成时会产生出不同的状态。
例如:当完成吃这个行为时,小猫小狗吃的就不一样,小猫吃猫粮,小狗吃狗粮
二、多态的实现:
在实现多态之前,先要了解向上转型和方法重写
1、向上转型:
就是创建对象时将子类给到父类,但是这个对象只能引用父类里的成员,不能引用子类里的
class Animal{
public String name;
public int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(this.name + "正在吃");
}
}
class Dog extends Animal{
public Dog(String name, int age) {
super(name, age);
}
public void bark(){
System.out.println(this.name + "汪汪叫");
}
}
class Bird extends Animal{
public Bird(String name, int age) {
super(name, age);
}
public void zhi(){
System.out.println(this.name + "吱吱叫");
}
}
public class Test {
public static void main(String[] args) {
Animal animal = new Dog("小黄",12);
//向上转型,将子类给到父类
animal.eat();
//animal.bark();错误,因为Animal里面没有
//只能访问自己特有的
}
}
结果
2、重写
重写要求:方法名相同,方法的参数列表相同(个数、顺序、类型),方法的返回值相同
例如:当我们在Dog类里重写了一个吃的方法时
class Animal{
public String name;
public int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(this.name + "正在吃");
}
}
class Dog extends Animal{
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat(){
System.out.println(this.name + "正在吃狗粮");
}
public void bark(){
System.out.println(this.name + "汪汪叫");
}
}
class Bird extends Animal{
public Bird(String name, int age) {
super(name, age);
}
public void zhi(){
System.out.println(this.name + "吱吱叫");
}
}
public class Test {
public static void main(String[] args) {
Animal animal = new Dog("小黄",12);
animal.eat();
}
}
结果:
却发现访问的是Dog里的eat
上述情况就叫动态绑定
发生前提:
1、需要发生向上转型
2、通过父类引用调用重写的方法
也有静态绑定:在编译的时候就确定调用了哪个方法
例如: public int add(int,int) public int add(int,int,int) 当调用add(1,2,3),就知道调用的是int add(int,int,int)这个方法
@Override这个注解是重写的意思,作用帮助检查,如果不满足重写要求就会报错
点左边的o⬆就能找到被重写的方法
注意Overload是重载
3、重写总结:
1、静态方法不能被重写
2、被private修饰的放法不能被重写
3、被final修饰的方法(密封方法)不能被重写
4、如果方法被重写,子类的权限要大于等于父类的权限
5、方法返回值可以不同:前提是返回值构成父子关系
public Animal eat(){}
public Dog eat(){}
两者构成了协变类型
方法的重载是一个类的多态性表现,方法的重写是子类父类的一种多态表现
动态绑定在编译的时候确实是Animal的eat方法,但是运行的时候,调用了Dog的eat(),此时我们就把他叫动态绑定。
4、发生向上转型的三种情况
(1)、直接赋值
(2)、方法传参
(3)、方法返回
public class Test {
public static void func(Animal animal1){
}
public static Animal func2(){
return new Dog("小黄",12);
}
public static void main(String[] args) {
Animal animal = new Dog("小黄",12);//直接赋值
//向上转型,将子类给到父类
func(new Dog("小黄",12));//方法传参
func2();//返回值
}
}
向上转型的优点:让代码实现更简单灵活
向上转型的缺点:不能调用到子类特有的方法
三、多态的概念
当animal引用的对象不一样,调用eat方法表现的行为不一样,此时就叫多态
也就是当同一类引用的对象类不一样时,调用相同的方法但得到的结果不一样,就是多态
举例:
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 Triangle extends Shape{
@Override
public void draw() {
System.out.println("画一个三角形");
}
}
public class test {
public static void drawMap(Shape shape){
shape.draw();
}
public static void main(String[] args) {
drawMap(new Rect());
drawMap(new Cycle());
drawMap(new Triangle());
}
}
使用多态的好处:
1、降低代码的“圈复杂度”,避免使用大量的if else
public class test {
public static void drawMap2(){
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();
}
}
public static void main(String[] args) {
drawMap2();
}
2、可扩展能力强
多态缺点:属性没有多态性,构造方法没有多态性,运行效率低
四、避免在构造方法中调用重写
class B {
public B() {
func();
}
public void func() {
System.out.println("B.func()");
}
}
class D extends B {
private int num = 1;
@Override
public void func() {
System.out.println("D.func() " + num);
}
}
public class test2 {
public static void main(String[] args) {
D d = new D();
}
}
结果:
说明在构造方法中也能发生动态绑定
构造D对象的同时会调用B的构造方法,B的构造方法中调用了func方法,此时会触发动态绑定,会调用到D中的func(),此时D对象自身还没有构造,此时num处在未初始化的状态。
所以在构造方法中尽量不要调用重写的方法
五、向下转型:
把父类引用给到子类
public static void main2(String[] args) {
Animal animal = new Dog("小燕",19);
//Dog dog = animal;
//报错原因,不是所有的动物都是狗,把大范围的东西给到小范围
//强转
Dog dog = (Dog)animal;
dog.bark();
}
但是存在不安全
public static void main2(String[] args) {
Animal animal = new Dog("小燕",19);
Bird bird = (Bird)animal;
//但是animal是狗,虽然代码没标错,但是运行出错,出现转化错误
}
解决方法加上if判断语句
public static void main(String[] args) {
Animal animal = new Dog("小燕",19);
if(animal instanceof Bird){
Bird bird = (Bird)animal;
}else
{
System.out.println("animal instanceof Bird not");
}
}