Java多态详解(2)

简介: Java多态详解(2)

向上转型和向下转型

向上转型

定义:实际就是创建一个子类对象,将其当作父类对象来使用

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

Animal animal = new Cat("元宝", 2);

animal是父类类型,但是可以引用子类对象,因为是从小范围到大范围的转换。

特点:

  1. 编译时多态性: 父类引用变量可以引用子类对象,编译器会在编译时检查引用变量的类型是否与对象的类型兼容。
  2. 运行时多态性: 在运行时,根据引用变量所指向的实际对象类型来调用对应的方法,实现方法的多态性。
  3. 限制方法访问: 向上转型后,只能调用父类中声明的方法,而不能直接调用子类新增的方法。

使用场景:1.直接赋值 2.方法传参 3.方法返回

举例一:直接赋值:

class Animal {
    void makeSound() {
        System.out.println("Animal makes a sound");
    }
}
 
class Dog extends Animal {
    void makeSound() {
        System.out.println("Dog barks");
    }
}
 
public class Main {
    public static void main(String[] args) {
        Animal animal = new Dog(); // 直接赋值
        animal.makeSound(); // 调用的是 Dog 类的方法
    }
}

举例二:方法传参

class Shape {
    void draw() {
        System.out.println("draw a shape");
    }
}
 
class Circle extends Shape {
    @Override
    void draw() {
        System.out.println("draw a circle");
    }
}
 
class Triangle extends Shape {
    @Override
    void draw() {
        System.out.println("draw a triangle");
    }
}
public class Test {
    public static void shapeDrawing(Shape s) {
        s.draw();
    }
 
    public static void main(String[] args) {
        Shape s1 = new Circle();
        Shape s2 = new Triangle();
 
        shapeDrawing(s1);
        shapeDrawing(s2);//方法传参,传递不同子类对象
    }
}

举例三:做返回值

class Vehicle {
    String getType() {
        return "Vehicle";
    }
}
 
class Car extends Vehicle {
    @Override
    String getType() {
        return "Car";
    }
}
 
class Bike extends Vehicle {
    @Override
    String getType() {
        return "Bike";
    }
}
 
public class Test {
    public static Vehicle getType(String type){
        if(type.equals("car")){
            return new Car();
        } else if(type.equals("bike")) {
            return new Bike();
        } else {
            return new Vehicle();
        }
    }
 
    public static void main(String[] args) {
        Vehicle v1 = getType("car");
        Vehicle v2 = getType("bike");
        Vehicle v3 = getType("plane");
 
        System.out.println(v1.getType());
        System.out.println(v2.getType());//方法返回,返回的实际上可能是子类对象
        System.out.println(v3.getType());
    }
}

向上转型的优点:让代码实现更加简单灵活

向上转型的缺点:不能调用到子类特有的方法

向下转型

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

class Animal1 {
    void makeSound() {
        System.out.println("Animal makes a sound");
    }
}
 
class Dog1 extends Animal1 {
    @Override
    void makeSound() {
        System.out.println("Dog barks");
    }
 
    void fetch() {
        System.out.println("Dog fetch the ball");
    }
}
 
public class Test1 {
    public static void main(String[] args) {
        Animal1 animal1 = new Dog1();//向上转型
 
        //向下转型
        if(animal1 instanceof Dog1) {
            Dog1 dog = (Dog1)animal1;//实例类型检查和向下转型
            dog.makeSound();//调用子类的方法
            dog.fetch();//调用子类特有的方法
        }
    }
}

向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛出异常。Java中为了提高向下转型的安全性,引入了instanceof(用于检查一个对象是否是指定类或其子类的实例),如果表达式的结果为true,则可以安全转换。

多态的优缺点

优点

假设有如下代码:

class Shape {
    //属性。。。
    public void draw() {
        System.out.println("画图形");
    }
}
 
class Rect extends Shape {
    @Override
    public void draw() {
        System.out.println("⎕");
    }
}
 
class Circle extends Shape {
    @Override
    public void draw() {
        System.out.println("◉");
    }
}
 
class Star extends Shape {
    @Override
    public void draw() {
        System.out.println("★");
    }
}

1.能够降低代码的“圈复杂度”,避免使用大量的if-else

圈复杂度:一种描述一段代码复杂程度的方式。一段代码如果平铺直叙,那么就比较简单容易理解,而如果有很多条件分支或者循环语句,就认为了解起来比较复杂。

因此我们可以简单粗暴的计算一段代码中条件语句和循环语句出现的个数,这个个数就称为“圈复杂度”,如果一个方法的圈复杂度太高,就需要考虑重构

不同公司对于圈复杂度的规范不一样,但一般不会超过10

例如我们现在需要的不只是打印一个形状了,而是多个形状,如果不基于多态,实现代码如下:

public static void drawShapes() {
    Rect rect = new Rect();
    Circle circle = new Circle();
    Star star = new Star();
    String[] shapes = {"circle", "rect", "circle", "rect", "star"};
    for(String shape : shapes) {
        if(shape.equals("circle")){
            circle.draw();
        } else if(shape.equals("rect")) {
            rect.draw();
        } else if(shape.equals("star")) {
            star.draw()
        }
    }
 
}

如果使用多态,则不必写这么多的if-else分支语句,代码更简单。

Shape[] shapes = {new Circle(), new Rect(), new Circle(), new Rect(), new Star()};
for(Shape shape : shapes) {
    shape.draw();
}

2.可扩展能力更强

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

class Triangle extends Shape {
    @Override 
    public void draw() {
        System.out.println("▲");
    }
}

对于类的调用者(主函数),只要创建一个新类的实例就可以了,改动成本很低。

而对于不用多态的情况,就要把drawShapes中的if-else进行一定修改,改动成本更高

缺点

代码运行效率降低

1.属性没有多态性:当父类和子类都有同名属性的时候,通过父类引用,只能引用父类自己的成员属性

2.构造方法没有多态性

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