Java面向对象:多态、应用场景、装箱和拆箱

多态

  • 概念:父类引用指向子类对象,从而产生多种形态。

    eg: Animal a = new Dog();
    
  • 二者具有直接或者间接的继承关系时,父类引用可指向子类对象,形成多态。

  • 父类引用仅可调用父类所声明的属性和方法,不可调用子类独有的属性和方法。

多态的两种应用场景

  • 场景① 父类类型引用作为方法的形参,实现多态,使方法参数的类型更为宽泛 (该父类的任何一个子类均可作为实参传入)

  • 场景② 使用父类类型作为方法返回值,实现多态,使方法可以可以返回不同的子类对象

public class TestApplyPolymorphic {
      public static void main(String[] args) {
            // 普通:自身引用指向自身对象
            Car car = new Car("小汽车", 45, 160000, "领克02"); //  this.brand = "领克02" 为子类独有属性
            car.run();
            // 多态:父类引用指向子类对象
            Vehicle veh = new Car("小汽车", 50, 180000, "领克01");
            veh.run(); // 方法覆盖 优先

            System.out.println("\n****************多态①:父类类型引用作为【形参】****************");

            Bus bus = new Bus("公交车", 60, 1000000, 55);
            Bicycle bic = new Bicycle("自行车", 15, 300, "蓝色");
            Employee emp = new Employee("工程师007");
            emp.goHome(car);
            emp.goHome(bus);
            emp.goHome(bic);

            System.out.println("\n****************多态②:父类类型引用作为【返回值】****************");
            Employee emp2 = new Employee("工程师996");
            Vehicle myVeh = emp2.buyVehicle(50);  // 价格可能由用户任意输入 >> 多态② >> 多态①
            emp2.goHome(myVeh);
            System.out.println("\n****************多态[向上造型](装箱):父类引用中保存真实子类对象****************");
            // 多态:父类引用指向子类对象
            Vehicle veh1 = new Car("小汽车", 80, 500000, "BMW X5");
            veh1.run();

            System.out.println("\n****************多态[向下造型](拆箱):父类引用强转回子类本身类型****************");
            // 取决于 line:24 行价格决定此时访问子类独有时是哪个子类
            if (myVeh instanceof Car) {
                  Car myCar = (Car) myVeh;
                  System.out.println("汽车独有品牌:"+ myCar.brand);
//                Bus myBus = (Bus) myVeh; // 运行则会抛出类型转换异常:java.lang.ClassCastException
//                System.out.println("公交独有座数:" + myBus.seatNum);
            } else if (myVeh instanceof Bus) {
                  Bus myBus = (Bus) myVeh;
                  System.out.println("公交独有座数:" + myBus.seatNum);
            } else if (myVeh instanceof Bicycle) {
                  Bicycle myBic = (Bicycle) myVeh;
                  System.out.println("自行车独颜色:" + myBic.color);
            }
      }
}
// 员工
class Employee {
      String name;

      public Employee() { }

      public Employee(String name) {
            this.name = name;
      }
      /**
       * 多态场景①:父类类型作为方法的【形参】,实现多态 (该父类任一个子类均可作为实参传入)
       * @param 父类类型引用
       */
      public void goHome(Vehicle veh) {
            System.out.print(name + "乘坐: ");
            veh.run(); // 父类依然遵循子类的覆盖方法优先,因此会打出来带子类方法的那句输出
      }

      /**
       * 多态场景②:父类类型作为方法【返回值】,实现多态,使方法可以可以返回不同的子类对象
       * @return 父类类型引用
       */
      public Vehicle buyVehicle(int money) { //money:万
            Vehicle veh = null; // 方法返回值,父类引用可存储不同子类对象的地址

            if (money >= 100) {
                  veh = new Bus("公交车", 66, 1100000, 50);
            } else if (money >= 30) {
                  veh = new Car("小汽车", 55, 150000, "领克03");
            } else {
                  veh = new Bicycle("自行车", 20, 500, "黄色");
            }
            return veh;
      }

      /*
      public void goHome(Bus bus) {  // 耦合高(模块与模块之间的关联程度,即耦合高=很松散)
            System.out.print(name + "正在乘坐");
            bus.run();
      }

      // 类内方法重载
      public void goHome(Bicyle bic) {
            System.out.print(name + "正在乘坐");
            bic.run();
      }
      */
}
// 交通工具
class Vehicle {
      String type; // 小汽车,公交车,自行车
      int speed;
      double price;

      public Vehicle() {}
      public Vehicle(String type, int speed, double price) {
            super();
            this.type = type;
            this.speed = speed;
            this.price = price;
      }
      public void run() {
            System.out.println("一辆价值" + price + "RMB的" + type + "正在以" + speed + "/H速度前进...");
      }
}
class Car extends Vehicle {
      String brand;

      public Car() {
            super();
      }
      public Car(String type, int speed, double price, String brand) {
            super(type, speed, price);
            this.brand = brand;
      }
      public void run() {
            System.out.println("一辆价值" + price + "RMB的" + brand +  "品牌的" + type + "正在以" + speed + "/H速度前进...");
      }
}
class Bus extends Vehicle {
      int seatNum;

      public Bus() {
            super();
      }
      public Bus(String type, int speed, double price, int seatNum) {
            super(type, speed, price);
            this.seatNum = seatNum;
      }
      public void run() {
            System.out.println("一辆价值" + price + "RMB的" + seatNum +  "座的" + type + "正在以" + speed + "/H速度前进...");
      }
}
class Bicycle extends Vehicle {
      String color;

      public Bicycle() {
            super();
      }
      public Bicycle(String type, int speed, double price, String  color) {
            super(type, speed, price);
            this.color = color;
      }
      public void run() {
            System.out.println("一辆价值" + price + "RMB的" + color +  "的" + type + "正在以" + speed + "/H速度前进...");
      }
}
输出:
一辆价值160000.0RMB的领克02品牌的小汽车正在以45/H速度前进...
一辆价值180000.0RMB的领克01品牌的小汽车正在以50/H速度前进...
****************多态①:父类类型引用作为【形参】****************
工程师007乘坐: 一辆价值160000.0RMB的领克02品牌的小汽车正在以45/H速度前进...
工程师007乘坐: 一辆价值1000000.0RMB的55座的公交车正在以60/H速度前进...
工程师007乘坐: 一辆价值300.0RMB的蓝色的自行车正在以15/H速度前进...
****************多态②:父类类型引用作为【返回值】****************
工程师996乘坐: 一辆价值150000.0RMB的领克03品牌的小汽车正在以55/H速度前进...
****************多态[向上造型](装箱):父类引用中保存真实子类对象****************
一辆价值500000.0RMB的BMW X5品牌的小汽车正在以80/H速度前进...
****************多态[向下造型](拆箱):父类引用强转回子类本身类型****************
汽车独有品牌:领克03

向****上****转型(装箱) - <****多态核心概念****>

  • 父类引用中保存真实子类对象。

  • eg: Animal a = new Dog(); // 对象层面的自动类型转换

  • 仅可调用父类中所声明的属性和方法(遵循属性遮蔽/方法覆盖原则)

向****下****转型(拆箱)

  • 将父类引用中的真实子类对象,强转回子类本身类型。

  • eg: Animal a = new Dog();

  • Dog dog = (Dog)a; // 对象层面的强制类型转换

Cat cat = (Cat)a; // Error: 不是真实子类对象new Dog(),编译OK,运行则会抛出类型转换异常:java.lang.ClassCastException

  • 只有转回子类真实类型,才可调用子类独有的属性和方法。

  • 向下转型前应该判断引用中的对象真实类型,保证类型转换的正确性

    • 语法: 父类引用 instanceof 类型 // 返回boolean类型结果
/* 从动物对象数组中找到目标动物子类 */
public class TestAnimal {
      public static void main(String[] args) {
            Animal[] as = new Animal[] {
                        new Dog("Pluto"),
                        new Cat("Tom"),
                        new Dog("Snoopy"),
                        new Cat("Garfield"),
                        new Dog("XiaoHei"),
                        new Cat("XiaoPang"),
            };

            for (int i = 0; i < as.length; i++) {
                  System.out.println(as[i].getName());
            }

            System.out.println("-------------------------------------");

            Dog[] dogs = getAllDog(as);
            for (int i = 0; i < dogs.length; i++) {
                  System.out.print(dogs[i].getName() + " ");
            }
      }

      /**
       * 返回指定相同子类的对象数组
       * @param as 父类动物对象数组
       * @return Dog[] 一组Dog对象
       */
      public static Dog[] getAllDog(Animal[] as) {
            // 0.计数器
            int count = 0;

            // 1.先数一遍要查找的同类子类对象数量
            for (int i = 0; i < as.length; i++) {
                  // 1.1 对数组中元素的类型进行判断
                  if (as[i] instanceof Dog) {
                        // 1.2 每找到一个,计数器自增+1
                        count++;
                  }
            }

            // 2.根据计数器结果,创建适合长度的目标数组
            Dog[] dogs = new Dog[count]; // 时间与空间的平衡、效率与安全的平衡

            // 3.定义一个目标数组有效元素个数
            int size = 0;

            // 4.将所有的目标同类子类对象,保存在目标数组中
            for (int i = 0; i < as.length; i++) {
                  // 4.1 判断是否为目标子类类型
                  if (as[i] instanceof Dog) {
                        // 4.2 保存子类对象到数组中 (多态-向下转型(拆箱)需强转)
                        dogs[size++] = (Dog) as[i];
                        //dogs[--count] = (Dog) as[i]; // 也可以,倒序
                  }
            }

            // 5.返回目标数组
            return dogs;
      }
}
class Animal {
      private String name;
      public Animal() {
            super();
      }
      public Animal(String name) {
            super();
            this.name = name;
      }
      public String getName() {
            return name;
      }
      public void setName(String name) {
            this.name = name;
      }
}
class Dog extends Animal {
      public Dog() {
            super();
      }

      public Dog(String name) {
            super(name);
      }
}
class Cat extends Animal {
      public Cat() {
            super();
      }

      public Cat(String name) {
            super(name);
      }
}

你可能感兴趣的:(Java面向对象:多态、应用场景、装箱和拆箱)