【Java】多态2

简介: 【Java】多态

3.向上转型和向下转型

向上转型和向下转型是我们学习多态的一个重要部分,在多态实现条件中需要满足通过父类的引用调用子类重写的方法,这时我们就需要用到向上转型。


3.1 向上转型

在上述代码中有一个打印机的多态代码。在测试类的主函数中这样的代码:


ColorPrinter colorPrinter = new ColorPrinter("彩色");
Printer printer = colorPrinter;

我们知道 ColorPrinter 是子类,Printer 是父类,实例化子类,把子类实例化的对象赋值给了父类类型对象,这就是向上转型


向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。


语法格式:父类类型 对象名 = new 子类类型()


Printer printer = new ColorPrinter("彩色");

还可以将其语法格式分开写,就是先实例化一个子类,然后将子类对象赋值给父类类型的变量


ColorPrinter colorPrinter = new ColorPrinter("彩色");
Printer printer = colorPrinter;

其.png


Printer 是父类类型,但是可以引用子类对象,因为是小范围向大范围的转换


向上转型:


只能访问父类中的成员属性

访问方法时如果子类中没有,则访问父类的,如果父类中也没有,则直接报错

访问方法时如果父类中没有 子类中有,则直接报错

访问方法时如果父类与子类中的方法重写,则访问子类的

访问方法时如果父类与子类中的方法重载,访问子类的重载方法,则直接报错

使用场景:


直接赋值

方法传参

方法返回

class Printer {
    public String name;
    Printer(String name) {
        this.name = name;
    }
    public void print() {
        System.out.println(name+"打印");
    }
}
class ColorPrinter extends Printer {
    ColorPrinter(String name) {
        super(name);
    }
    @Override
    public void print() {
        System.out.println(name+"打印彩色的");
    }
}
class BWPrinter extends Printer {
    BWPrinter(String name) {
        super(name);
    }
    @Override
    public void print() {
        System.out.println(name+"打印黑白的");
    }
}

还是拿这些继承体系下的类来举例


①直接赋值


public class Test {
    public static void main(String[] args) {
        Printer printer = new ColorPrinter("彩色打印机");
        printer.print();
    }
}

通过 Test类 的主方法中 Printer printer = new ColorPrinter("彩色打印机") 这句代码直接赋值,来完成了向上转型。


②方法传参


public class Test {
    public static void fun(Printer printer) {
        printer.print();
    }
    public static void main(String[] args) {
        ColorPrinter colorPrinter = new ColorPrinter("彩色打印机");
        fun(colorPrinter);
    }
}

将实例化的子类对象通过方法传参的形式,传给父类对象,来完成向上转型。


③方法返回


public class Test {
    public static Printer buyPrinter(String name) {
        if ("彩色打印机".equals(name)) {
            return new ColorPrinter("彩色打印机");
        } else if ("黑白打印机".equals(name)) {
            return new BWPrinter("黑白打印机");
        } else {
            return null;
        }
    }
    public static void main(String[] args) {
        Printer printer = buyPrinter("彩色打印机");
        printer.print();
    }
}


通过方法返回实例化对象的方式,进行向上转型。根据方法的形参来判断需要实例化那个子类对象


注:父类引用哪个子类,当通过父类引用去访问重写的方法时,则会访问父类引用的子类中的重写方法


3.2 向下转型

向下转型:将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换


前.png


向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入 了 instanceof ,如果该表达式为true,则可以安全转换


class Printer {
    public String name;
    Printer(String name) {
        this.name = name;
    }
    public void print() {
        System.out.println(name+"打印");
    }
}
class ColorPrinter extends Printer {
    ColorPrinter(String name) {
        super(name);
    }
    @Override
    public void print() {
        System.out.println(name+"打印彩色的");
    }
    public void print2() {
        System.out.println(name+"激光打印");
    }
}
public class Test {
    public static void main(String[] args) {
        Printer printer = new ColorPrinter("彩色打印机");
        printer.print();
        //printer.print2();直接报错
        //此时可以采用向下转型
        //如果直接向下转型就很不安全,我们就需要instanceof来判断
        if (printer instanceof ColorPrinter) {
            ColorPrinter colorPrinter = (ColorPrinter) printer;
            colorPrinter.print2();
        }
    }
}


4.多态的优缺点

4.1 多态的优点

假设有如下代码:


class Draw {
    public void fun() {
        System.out.println("画画");
    }
}
class Square extends Draw {
    public void fun() {
        System.out.println("正方形");
    }
}
class Circular extends Draw {
    public void fun() {
        System.out.println("圆");
    }
}


多态的好处:


①能够降低代码的 "圈复杂度", 避免使用大量的 if - else


那么什么是圈复杂度呢?


圈复杂度是一种描述一段代码复杂程度的方式。一段代码如果平铺直叙,那么就比较简单容易理解。而如果有很多的条件分支或者循环语句, 就认为理解起来更复杂。因此我们可以计算一段代码中条件语句和循环语句出现的个数, 这个个数就称为 "圈复杂度"。如果一个方法的圈复杂度太高, 就需要考虑重构。


如果我们现在需要打印多个图形,如果不用多态,就需要用到多个 if - else :


public class Test {
    public static void main(String[] args) {
        Square square = new Square();
        Circular circular = new Circular();
        String[] arr = {"square","circular"};
        for (String tmp : arr){
            if (tmp.equals("square")) {
                square.fun();
            } else if(tmp.equals("circular")) {
                circular.fun();
            }
        }
    }
}

如果使用使用多态, 则不必写这么多的 if - else 分支语句:


public class Test {
    public static void func(Draw draw) {
        draw.fun();
    }
    public static void main(String[] args) {
        func(new Square());
        func(new Circular());
    }
}

②可扩展能力更强


如果要新增一种新的形状,使用多态的方式代码改动成本也比较低


对于类的调用者来说,只要创建一个新类的实例就可以了,改动成本很低


4.2 多态的缺点

多态缺陷:代码的运行效率降低。 1. 属性没有多态性 当父类和子类都有同名属性的时候,通过父类引用,只能引用父类自己的成员属性 2. 构造方法没有多态性


5.避免在构造方法中调用重写的方法

class Draw {
    public Draw() {
        fun();
    }
    public void fun() {
        System.out.println("画画");
    }
}
class Square extends Draw {
    public Square() {
        super();
    }
    int num = 1;
    public void fun() {
        System.out.println("正方形"+num);
    }
}
public class Test {
    public static void main(String[] args) {
        Draw draw = new Square();
    }
}


运行结果:

我.png



构造 Square 对象的同时, 会调用 Draw 的构造方法.

Square 的构造方法中调用了 fun 方法, 此时会触发动态绑定, 会调用到 Draw 中的 fun

此时 Square 对象自身还没有构造, 此时 num 处在未初始化的状态, 值为 0。如果具备多态性,num的值应该是1.

所以在构造函数内,尽量避免使用实例方法,除了final和private方法。


相关文章
|
5月前
|
算法 Java 程序员
在Java的编程世界里,多态不仅仅是一种代码层面的技术,它是思想的碰撞,是程序员对现实世界复杂性的抽象映射,是对软件设计哲学的深刻领悟。
在Java的编程世界里,多态不仅仅是一种代码层面的技术,它是思想的碰撞,是程序员对现实世界复杂性的抽象映射,是对软件设计哲学的深刻领悟。
83 9
|
5月前
|
Java 开发者
在Java面向对象编程的广阔海洋中,多态犹如一股深邃的潜流,它推动着代码从单一走向多元,从僵化迈向灵活。
在Java面向对象编程的广阔海洋中,多态犹如一股深邃的潜流,它推动着代码从单一走向多元,从僵化迈向灵活。
45 7
|
5月前
|
Java 开发者
那些年,我们一同踏入Java编程的大门,多态,这个充满魔法的名字,曾无数次点亮我们探索面向对象编程的热情。
那些年,我们一同踏入Java编程的大门,多态,这个充满魔法的名字,曾无数次点亮我们探索面向对象编程的热情。
53 5
|
5月前
|
Java 程序员
让我们一起探讨Java多态的奥秘,看看它是如何打破“一刀切”的局限,让我们的代码更加生动多彩
让我们一起探讨Java多态的奥秘,看看它是如何打破“一刀切”的局限,让我们的代码更加生动多彩
46 5
|
5月前
|
Java 程序员
Java中的继承和多态:理解面向对象编程的核心概念
【8月更文挑战第22天】在Java的世界中,继承和多态不仅仅是编程技巧,它们是构建可维护、可扩展软件架构的基石。通过本文,我们将深入探讨这两个概念,并揭示它们如何共同作用于面向对象编程(OOP)的实践之中。你将了解继承如何简化代码重用,以及多态如何为程序提供灵活性和扩展性。让我们启程,探索Java语言中这些强大特性的秘密。
|
3月前
|
存储 Java 测试技术
Java零基础-多态详解
【10月更文挑战第10天】Java零基础教学篇,手把手实践教学!
41 4
|
3月前
|
Java 编译器 程序员
Java多态背后的秘密:动态绑定如何工作?
本文介绍了Java中多态的实现原理,通过动态绑定和虚拟方法表,使得父类引用可以调用子类的方法,增强了代码的灵活性和可维护性。文中通过具体示例详细解析了多态的工作机制。
80 4
|
4月前
|
Java 编译器
封装,继承,多态【Java面向对象知识回顾①】
本文回顾了Java面向对象编程的三大特性:封装、继承和多态。封装通过将数据和方法结合在类中并隐藏实现细节来保护对象状态,继承允许新类扩展现有类的功能,而多态则允许对象在不同情况下表现出不同的行为,这些特性共同提高了代码的复用性、扩展性和灵活性。
封装,继承,多态【Java面向对象知识回顾①】
|
3月前
|
Java
java继承和多态详解
java继承和多态详解
55 5
|
4月前
|
Java 编译器
Java——类与对象(继承和多态)
本文介绍了面向对象编程中的继承概念,包括如何避免重复代码、构造方法的调用规则、成员变量的访问以及权限修饰符的使用。文中详细解释了继承与组合的区别,并探讨了多态的概念,包括向上转型、向下转型和方法的重写。此外,还讨论了静态绑定和动态绑定的区别,以及多态带来的优势和弊端。
93 9
Java——类与对象(继承和多态)