Bootstrap

Java初学-多态

Java初学6.6.2-多态的应用

多态数组:数组定义类型为父类类型,里面的保存的实际元素为子类类型。

在Java中,多态数组是一个强大的特性,它允许你定义一个数组,其元素类型为某个基类(父类),但实际存储的是该基类的子类实例。这利用了Java的向上转型(upcasting),即子类对象可以被赋值给父类引用。

下面是一个使用多态数组的例子,先定义一个基类 Animal 和两个子类 Dog 和 Cat,并且每个类都有一个 speak 方法:

public class Animal {

    public void speak() {

        System.out.println("Some generic animal sound");

    }

}

public class Dog extends Animal {

    public void speak() {

        System.out.println("Woof!");

    }

}

public class Cat extends Animal {

    public void speak() {

        System.out.println("Meow!");

    }

}

接下来,可以创建一个 Animal 类型的数组,并在其中存储 Dog 和 Cat 实例:

public class Main {

   public static void main(String[] args) {

        Animal[] animals = new Animal[2]; // 定义一个Animal类型的数组

        animals[0] = new Dog(); // 存储Dog实例

        animals[1] = new Cat(); // 存储Cat实例

        for (int i=0;i<animals.length;i++) {

            Animals[i].speak(); // 调用speak方法,这里体现了多态性

        }

    }

运行上述代码,输出:

Woof!

Meow!

在这个例子中,虽然数组的声明类型是 Animal,但我们可以将 Dog 或 Cat 实例存储在数组中。当我们通过数组遍历并调用 speak 方法时,实际上调用的是每个对象的特定实现,而不是 Animal 类中的默认实现。这就是多态性的体现:相同的调用在运行时会表现出不同的行为,具体取决于对象的实际类型。

package PolyMorphicTest;

public class PolyTest0003 {
    public static void main(String[] args){
        PolyTest0003A[] p = new PolyTest0003A[5];
        p[0] = new PolyTest0003A("与姜昆",22);
        p[1] = new PolyTest0003B("帐篷非",23,59);
        p[2] = new PolyTest0003B("勺子长",22,59.9);
        p[3] = new PolyTest0003C("坚毅许安",23,19820);
        p[4] = new PolyTest0003C("大帅哥",18,120000);
        //编译类型都是PolyTest0003A,运行类型A,B,B,C,C。
        /*p[0].printPolyTest0003();
        p[1].printPolyTest0003();
        p[2].printPolyTest0003();
        p[3].printPolyTest0003();
        p[4].printPolyTest0003();*/
        //循环遍历数组:
        for(int i=0;i<p.length;i++){
            p[i].printPolyTest0003();//动态绑定机制。

        }
        //调用子类中的特有方法,需要使用向下转型。
        if (p[1] instanceof PolyTest0003B) {
            /*PolyTest0003B x = (PolyTest0003B) p[1];
            x.uniquePolyTest0003B();等价于:*/
            ((PolyTest0003B) p[1]).uniquePolyTest0003B();
        }
        if (p[3] instanceof PolyTest0003C) {
            ((PolyTest0003C) p[3]).uniquePolyTest0003C();
        }
    }
}
class PolyTest0003A {
    private String name;
    private int age;
    public PolyTest0003A(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void printPolyTest0003() {
        System.out.print(getName() +" " + getAge() + " ");
    }
}
class PolyTest0003B extends PolyTest0003A {
    private double score;
    public PolyTest0003B(String name, int age, double score) {
        super(name, age);
        this.score = score;
    }
    public double getScore() {
        return score;
    }
    public void setScore(double score) {
        this.score = score;
    }
    public void printPolyTest0003() {
        super.printPolyTest0003();
        System.out.println(getScore());
    }
    public void uniquePolyTest0003B() {
        System.out.println("嘻嘻~");
    }
}
class PolyTest0003C extends PolyTest0003A {
    private double salary;
    public PolyTest0003C(String name, int age, double salary) {
        super(name, age);
        this.salary = salary;
    }
    public double getSalary() {
        return salary;
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }
    public void printPolyTest0003() {
        super.printPolyTest0003();
        System.out.println(getSalary());
    }
    public void uniquePolyTest0003C() {
        System.out.println("哈哈~");
    }

}

多态参数:在Java中,多态参数主要通过两种方式实现:方法重载(overloading)和方法重写(overriding)。然而,在讨论多态参数时,我们通常指的是后者,即方法重写,因为这直接涉及到对象的多态性和动态绑定。

方法重写(Overriding)实现多态参数

方法重写发生在子类中,子类可以重写(override)从父类继承的方法。这意味着子类提供了自己版本的实现,这个实现可以有不同的行为。当我们通过父类类型的引用调用一个方法时,实际执行的是由引用所指向的对象类型所定义的方法,这就是动态绑定(dynamic binding)。

class Animal {

    void makeSound() {

        System.out.println("Some generic sound");

   }

}

class Dog extends Animal {

    @Override

    void makeSound() {

        System.out.println("Woof!");

    }

}

class Cat extends Animal {

    @Override

    void makeSound() {

        System.out.println("Meow!");

    }

}

public class Main {

    public static void main(String[] args) {

        Animal myAnimal = new Animal();

        Animal myDog = new Dog();

        Animal myCat = new Cat();

        makeSound(myAnimal);

        makeSound(myDog);

        makeSound(myCat);

    }

   public static void makeSound(Animal animal) {

        animal.makeSound();

    }

}

在上述代码中,makeSound 方法是多态的,因为它接受一个 Animal 类型的参数。当我们通过 makeSound 方法传递 Dog 或 Cat 对象时,实际执行的是这些子类重写后的方法,而不是 Animal 类中的方法。这是因为Java使用动态绑定,调用哪个方法取决于运行时对象的实际类型。

package PolyMorphicTest;
public class PolyTest0004 {
    public static void main(String[] args) {
        NormalEmployee n = new NormalEmployee("浴巾阿坤",16000);
        System.out.println(n.getSalary());
        Manager m = new Manager("勺子啊擦",300,900);
        System.out.println(m.getSalary());
        /*PolyTest0004 polyTest0004 = new PolyTest0004();//如果一个方法不是静态的(即没有使用 static 关键字声明),那么它必须通过一个类的实例来调用。
        polyTest0004.show(n);
        polyTest0004.show(m);
        polyTest0004.show01(n);
        polyTest0004.show01(m);*/
        PolyTest0004.show(n);
        PolyTest0004.show(m);
        PolyTest0004.show01(n);
        PolyTest0004.show01(m);
    }
        /*public void show(PolyTest0004Employee a){
             a.getSum();
        }
        public void show01(PolyTest0004Employee a){
        if(a instanceof NormalEmployee){
            ((NormalEmployee) a).NormalWork();
        }else if(a instanceof Manager){
            ((Manager) a).Manage();
        }
        }*/
        public static void show(PolyTest0004Employee a){
            a.getSum();
        }
//将这些方法设置为静态的,那么在 main 方法中,不再需要创建 PolyTest0004 的实例,而是可以直接调用这些静态方法。
    public static void show01(PolyTest0004Employee a){
        if(a instanceof NormalEmployee){
            ((NormalEmployee) a).NormalWork();
        } else if(a instanceof Manager){
            ((Manager) a).Manage();
        }
    }

}
class PolyTest0004Employee {
    private String name;
    private double  salary;
    public PolyTest0004Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }
    public String getName() {
        return name;
    }
    public double getSalary() {
        return salary;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }
    public void getSum(){
        System.out.println(16 * getSalary());
    }
}
class NormalEmployee extends PolyTest0004Employee {
    public NormalEmployee(String name, double salary) {
        super(name, salary);
    }
    public void getSum(){
        System.out.println(getName() + ": Normal Employee Salary " + 12 * getSalary());
    }
    public void NormalWork(){
        System.out.println("Normal Work ");
    }
}
class Manager extends PolyTest0004Employee {
    private double bonus;
    public Manager(String name, double salary, double bonus) {
        super(name, salary);
        this.bonus = bonus;
    }
    public double getBonus() {
        return bonus;
    }
    public void setBonus(double bonus) {
        this.bonus = bonus;
    }
    public void getSum(){
        System.out.println(getName() + ": Manager Salary " + 14 * getSalary() + "+" + getBonus());
    }
    public void Manage(){
        System.out.println("Manager Work ");
    }
}

;