我在VScode学Java多态(Java多态、instanceof)

news2024/9/23 7:22:31
Java的多态(Polymorphism)是面向对象编程中的一种特性,它允许不同的对象能够以统一的方式进行访问和操作。
	它允许一个类的实例在运行时表现出多种形态。
Java多态的实现主要依赖于两个基本概念:继承和方法重写。

在Java中,一个子类可以继承父类的方法,并且可以通过重写这些方法来实现自己的特定行为。当我们创建一个对象时,它可以指向自身的类类型,也可以指向任何父类或者实现的接口类型。这就是Java多态性的核心思想:一个对象具有多种外观和行为,这取决于使用它的上下文。

Java多态的好处是可以提高代码的重用性和可维护性,使得代码更加灵活和可扩展。例如,一个方法可以接受一个基类(如Object)作为参数,然后在运行时传入一个子类的实例,这样就可以处理各种不同的对象类型,而无需重写这个方法。

文章目录

  • 在Java中,多态性的实现方式有两种:
      • 表现出多态度的过程:
        • 简要说明:`父类类型` `类型名称` `=` `子类对象`
        • 详细:
    • Java中使用多态的时机通常是在面向对象编程的场景中,特别是在以下情况下比较合适:
    • Java要实现多态性,需要以下几个要点:
      • 0.其他:
      • 1. **继承关系(创建父类和子类):
      • 2. **方法重写(Override):**
      • 3. **父类引用和子类对象:**
      • 4. **运行时绑定(Runtime Polymorphism):**
      • 5. **使用抽象类或接口(可选):**
      • 多态调用成员的特点
  • instanceof 匹配判断成功后将对象强制转换为指定的类
      • 方式壹
          • 代码1:仅仅判断是不是某类
          • 代码2: 匹配后强转
      • 方拾贰:条件判断中同时进行类型检查和类型转换
          • 举例代码:

父类引用引用一个具有子类身份信息的对象时,就创建了一个多态关系的实现效果。

在Java中,多态性的实现方式有两种:

Parent obj = new Child();
obj.show(); // 调用子类的方法

  1. 编译时多态:也称为静态多态,通过方法的重载实现。方法重载是指在一个类中定义多个同名的方法,但参数列表不同,编译器会根据传入的参数类型来选择调用哪个方法。

  2. 运行时多态:也称为动态多态,通过方法的重写实现。方法重写是指子类重新定义了父类中具有相同名称和参数列表的方法,子类对象在运行时会根据具体的对象类型来调用对应的方法。

运行时多态性的实现需要满足以下条件:

  • 存在继承关系:子类继承自父类。
  • 存在方法重写:子类重写了父类的方法。
  • 父类引用指向子类对象:通过父类的引用指向子类的对象,在运行时会根据实际对象的类型调用相应的方法。

表现出多态度的过程:

多态性的优点在于它增加了代码的灵活性和可扩展性,使得代码更易于维护和重用。

简要说明:父类类型 类型名称 = 子类对象

详细:

  1. 父类和子类关系的建立:

    class Parent {
        void show() {
            System.out.println("Parent's show method");
        }
    }
    
    class Child extends Parent {
        void show() {
            System.out.println("Child's show method");
        }
    }
    
  2. 使用多态的情况:

    Parent obj1 = new Parent();
    Parent obj2 = new Child();
    
    obj1.show(); // 调用父类的方法
    obj2.show(); // 调用子类的方法
    
  3. 方法重写(Override):

    @Override
    void show() {
        System.out.println("Child's overridden show method");
    }
    
  4. 父类引用调用子类方法:

    Parent obj = new Child();
    obj.show(); // 调用子类的方法
    

Java中使用多态的时机通常是在面向对象编程的场景中,特别是在以下情况下比较合适:

  1. 继承关系:当有多个类存在继承关系时,可以通过多态来处理它们的对象,从而实现更灵活的代码结构和简化代码逻辑。

  2. 方法的参数:如果一个方法需要接收不同类型的对象,并对它们进行相似的操作,使用多态可以使代码更加通用和易于扩展。

  3. 方法的返回值:当方法返回类型是基类或接口类型,但实际返回的是派生类的实例,可以使用多态来实现。

  4. 集合的使用:在使用集合(如List、Set、Map)时,可以使用多态来存储不同类型的对象,并且通过统一的接口来进行操作。

总的来说,多态使代码更加灵活、可维护性更高,能够提高代码的重用性和扩展性。

Java要实现多态性,需要以下几个要点:

0.其他:

  1. 向上转型:将子类对象赋值给父类引用。这样做可以实现多态性,但只能调用父类中定义的方法。
  2. 向下转型:将父类引用转换为子类对象。需要使用强制类型转换符进行转换。但需要注意的是,向下转型可能会引发ClassCastException异常,因此在转型之前需要进行类型检查(使用instanceof)。

1. **继承关系(创建父类和子类):

** 首先,你需要设计一个父类(基类),其中包含一些通用属性和方法。然后,创建一个或多个子类(派生类),它们继承了父类的属性和方法,并可以添加自己的特定属性和方法。

class Shape {
    void draw() {
        System.out.println("Drawing a shape");
    }
}

class Circle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a circle");
    }
}

class Rectangle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a rectangle");
    }
}

2. 方法重写(Override):

在子类中,你可以使用@Override注解来重写父类的方法。确保重写的方法具有相同的方法签名(名称、参数列表和返回类型),以便在多态性中起作用。

3. 父类引用和子类对象:

’使用父类的引用变量来引用子类的对象,这是实现多态性的关键。这允许你在编码时保持灵活性,可以在运行时决定调用哪个类的方法。

Shape myShape1 = new Circle();//`Shape` 是父类引用,而 `new Circle();` 是子类对象。
Shape myShape2 = new Rectangle();

myShape1.draw(); // 输出:Drawing a circle
myShape2.draw(); // 输出:Drawing a rectangle

多态性允许我们使用父类的引用来引用子类的对象,这是因为子类对象是可以赋值给父类引用的。这有助于实现代码的灵活性和可扩展性。

Shape myShape1 = new Circle(); 这行代码中,我们创建了一个 Circle 类的对象,并将其赋值给 Shape类型的引用变量 myShape1。由于 Circle Shape 的子类,这种赋值是合法的。这意味着虽然myShape1的类型是 Shape,但它指向的实际上是一个 Circle 类型的对象。

通过这种方式,我们可以使用通用的 Shape 引用来引用不同的具体形状对象,从而实现了多态性和继承的概念。这种设计模式允许我们在代码中以一种更抽象的方式操作对象,同时保留了具体对象的特定功能。

4. 运行时绑定(Runtime Polymorphism):

当通过父类引用调用方法时,Java会在运行时动态地确定实际调用的方法,这称为运行时绑定。这意味着你可以在不同的上下文中使用相同的方法调用,但实际执行的是不同子类的方法。

5. 使用抽象类或接口(可选):

如果你希望定义一组共享的方法签名,可以使用抽象类或接口。抽象类可以提供部分实现,而接口则强制实现所有方法。这使得多态性更加灵活,可以在不同类之间共享更多的行为。

interface Sound {
    void makeSound();
}

class Dog implements Sound {
    @Override
    public void makeSound() {
        System.out.println("Dog barks");
    }
}

class Cat implements Sound {
    @Override
    public void makeSound() {
        System.out.println("Cat meows");
    }
}

综上所述,实现多态性需要创建继承关系、重写方法、使用父类引用和子类对象、运行时绑定以及可能的抽象类或接口。这些概念共同使多态性成为面向对象编程中的强大特性,提高了代码的灵活性和可维护性。

多态调用成员的特点

变量调用:编译看左边,运行也看左边
方法调用:编译看左边,运行看右边

  1. 变量调用成员时,编译时会根据变量的声明类型(左边)来确定可访问的成员,运行时也会使用变量的实际类型(左边)来确定实际执行的代码。

编译时看左边: 在编译阶段,编译器会检查父类中是否存在被调用的成员变量。如果存在,编译通过;如果不存在,编译失败。
运行时也看左边: 在运行阶段,程序实际获取的是左边父类中的成员变量的值,而不考虑实际对象的类型。

  1. 方法调用时,编译时会根据变量的声明类型(左边)来确定可调用的方法,但在运行时会根据实际对象的类型(右边)来决定实际执行的方法。

编译时看左边: 在编译阶段,编译器会检查变量的声明类型(左边)来确定可调用的方法。如果左边的类型没有声明被调用的方法,编译会报错,即使实际对象具有相应的方法。
运行时看右边: 在运行阶段,方法调用会根据实际对象的类型(右边)来决定实际执行的方法。即使使用父类的引用,程序也会根据实际对象的类型来调用相应的方法,这被称为动态方法分派。

这 种行为允许你在运行时通过替换对象实例来实现不同的行为,这是面向对象编程中多态性的一个关键概念。

class Animal {
    public void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Dog barks");
    }
}

class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Cat meows");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myAnimal1 = new Dog();  // 编译看左边,运行也看左边
        Animal myAnimal2 = new Cat();  // 编译看左边,运行也看左边

        myAnimal1.makeSound();  // 编译看左边,运行看右边 ("Dog barks")
        myAnimal2.makeSound();  // 编译看左边,运行看右边 ("Cat meows")
    }
}

在这里插入图片描述

instanceof 匹配判断成功后将对象强制转换为指定的类

使用 instanceof 进行类型检查和强制类型转换时,应该确保类型转换是安全的,即要确保对象的实际类型与你尝试转换的类型是相符的。如果类型不匹配,会在运行时抛出 ClassCastException 异常。

方式壹

if (object instanceof MyClass) {
    MyClass myObject = (MyClass) object;
    // 此时可以使用 myObject 来访问 MyClass 特有的方法和属性
}

在这里,object 是要检查的对象,MyClass 是要检查的类名。如果 object 是 MyClass 类的实例或者其派生类的实例,条件就会为真,代码块会被执行。`

代码1:仅仅判断是不是某类
class ParentClass {
    // Contents of the parent class
}

class ChildClass1 extends ParentClass {
    // Contents of the first child class
}

class ChildClass2 extends ParentClass {
    // Contents of the second child class
}

public class Main {
    public static void main(String[] args) {
        ParentClass obj = new ParentClass(); // This can be an instance of any class
        
        if (obj instanceof ChildClass1) {
            System.out.println("obj is an instance of ChildClass1");
        } else if (obj instanceof ChildClass2) {
            System.out.println("obj is an instance of ChildClass2");
        } else {
            System.out.println("obj is not an instance of ChildClass1 or ChildClass2");
        }
    }
}

在这个示例中,我们首先创建了一个 ParentClass 的实例,然后使用 instanceof 运算符检查它是否是 ChildClass1 或 ChildClass2 的实例。如果都不是,就输出相应的提示信息。

请注意,这个示例中的类和实例是一种简化,实际情况可能会更加复杂。不过,基本的 instanceof 使用方式和逻辑与这个示例类似。

代码2: 匹配后强转
class Animal {
    public void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    public void makeSound() {
        System.out.println("Dog barks");
    }
    
    public void fetch() {
        System.out.println("Dog fetches the ball");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myAnimal = new Dog();

        if (myAnimal instanceof Dog) {
            Dog myDog = (Dog) myAnimal;
            myDog.fetch(); // 可以调用 Dog 特有的方法
        }

        myAnimal.makeSound(); // 输出:Dog barks
    }
}

方拾贰:条件判断中同时进行类型检查和类型转换

if (object instanceof MyClass myObject) {
    
    // 此时可以使用 myObject 来访问 MyClass 特有的方法和属性
}
举例代码:
class MyClass {
    public void myMethod() {
        System.out.println("MyClass method");
    }
}

public class Main {
    public static void main(String[] args) {
        Object object = new MyClass();

        if (object instanceof MyClass myObject) {
            myObject.myMethod(); // 可以直接使用 myObject 调用 MyClass 的方法
        }
    }
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/855181.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

程序员的趣闻:神奇Bug与不可思议的技术世界

文章目录 Bug本身情况发现Bug的过程怎么对待这个Bug其他感受 程序员的世界充满了各种离奇而又难以置信的趣闻,其中不乏那些令人目瞪口呆的神奇Bug。有时候,这些故事不仅令人捧腹大笑,还展现了技术世界的多姿多彩。让我们走进这个充满惊奇的领…

Java集合容器详解:ArrayList、LinkedList和HashMap、HashTable及其区别

文章目录 一、简介二、ArrayList详解2.1 动态数组2.2 扩容机制2.3 特点2.4 操作 三、LinkedList详解3.1 双向链表结构3.2 双向链表结构3.3 操作 四、HashMap详解4.1 概述4.2 内部实现4.2.1 哈希表结构4.2.2 散列冲突解决4.2.3 扩容机制 4.3 版本差异4.4 实操 五、HashTable5.1 …

安卓:LitePal操作数据库

目录 一、LitePal介绍 常用方法: 1、插入数据: 2、更新数据: 3、删除数据: 4、查询数据: 二、LitePal的基本用法: 1、集成LitePal: 2、创建LitePal配置文件: 3、创建模型类…

Vue+Vue Router+TailwindCss+Daisyui部署

一、构建Vue项目 > npm init vuelatest > cd <your-project-name> > npm install > npm run dev 二、设置IDEA JS版本 三、安装Tailwindcss Install Tailwind CSS with Vite - Tailwind CSS npm install -D tailwindcss postcss autoprefixer npx tai…

Linux下匿名管道简单模拟进程间通信

Linux下匿名管道简单模拟进程间通信 文章目录 Linux下匿名管道简单模拟进程间通信在这里插入图片描述1.引言2.具体实现2.1创建管道2.2创建子进程 && 通信(子进程写入)2.3关闭对应fd 3.结果 1.引言 ​ ​ 首先&#xff0c;管道是一种半双工的单向进程间通信方式&#…

有哪些简单的AI绘画软件?

随着人工智能技术的不断发展&#xff0c;越来越多的人工智能绘画软件出现了。人工智能绘画软件利用人工智能技术&#xff0c;通过计算机自动生成或辅助生成艺术作品。人工智能绘画软件通常集成了深度学习、计算机视觉和自然语言处理技术&#xff0c;可以模拟人类的创作过程&…

【数据结构与算法】十大经典排序算法-插入排序

&#x1f31f;个人博客&#xff1a;www.hellocode.top &#x1f3f0;Java知识导航&#xff1a;Java-Navigate &#x1f525;CSDN&#xff1a;HelloCode. &#x1f31e;知乎&#xff1a;HelloCode &#x1f334;掘金&#xff1a;HelloCode ⚡如有问题&#xff0c;欢迎指正&#…

【Shell】基础语法(三)

文章目录 一、Shell基础语法1. 位置参数和特殊变量2. 输入输出3. 管道4. 文件重定向5. 函数6. 脚本调试方法 二、Shell高级和正则表达式1. sort命令2. uniq命令3. wc命令4. grep命令5. find命令6. xargs7. sed命令8. crontab 一、Shell基础语法 1. 位置参数和特殊变量 $0 …

循环队列详解

1. 循环队列 1.1 概念及结构 循环队列是一种特殊类型的队列数据结构&#xff0c;也被称为”唤醒缓冲器“。它在数组的基础上实现了循环利用空间的功能。在循环队列中&#xff0c;队尾和队头之间形成了一个循环&#xff0c;当队尾指针“追上”队头指针时&#xff0c;队列不再继…

IDEA设置Tabs多行显示的方法

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 前言 在开发的时候、不知不觉我们就会打开很多代码页。如果打开的页面…

在线原型设计工具有好用的吗?就是这10个

随着设计工作的不断发展&#xff0c;原型设计在设计工作中越来越重要&#xff0c;而在线原型设计工具在减轻了设计师工作负担的同时也提高了设计师的工作效率&#xff0c;今天本文将为大家推荐10个能在线使用的原型设计工具&#xff0c;一起来看看吧&#xff01; 1、即时设计 …

CDC 数据复制:技术、权衡、见解

推荐&#xff1a;使用NSDT场景编辑器助你快速搭建可编辑的3D应用场景 在本文中&#xff0c;我将定义 CDC 数据复制&#xff0c;简要讨论最常见的用例&#xff0c;然后讨论常见技术及其权衡。最后&#xff0c;我将提供一些我作为数据集成公司Dataddo的首席执行官和创始人所学到…

使用logback异步打印日志

文章目录 一、介绍二、运行环境三、演示项目1. 接口2. 日志配置文件3. 效果演示4. 异步输出验证 四、异步输出原理五、其他参数配置六、源码分析1. 同步输出2. 异步输出 七、总结 一、介绍 对于每一个开发人员来说&#xff0c;在业务代码中添加日志是至关重要的&#xff0c;尤…

CSS:弹性盒子模型详解(用法 + 例子 + 效果)

目录 弹性盒子模型flex-direction 排列方式 主轴方向换行排序控制子元素缩放比例缩放是如何实现的&#xff1f; 控制子元素的对其方式justify-content 横向 对齐方式align-items 纵向 对齐方式 align-content 多行 对齐方式 弹性盒子模型 flex-direction 排列方式 主轴方向 f…

webshell免杀项目-Auto-JSPwebshell(五)

Auto-JSPwebshell/jsp免杀/webshell免杀/自动生成 项目地址&#xff1a; https://github.com/G0mini/Bypass 具体使用请参考&#xff1a; https://mp.weixin.qq.com/s/9-__B0MBRSXHla6O0KU7Gg

PCB制造中铜厚度的重要性

电子产品中的PCB是现代电子设备中不可或缺的一部分。在PCB制造过程中&#xff0c;铜厚度是一个非常重要的因素。正确的铜厚度可以保证电路板的质量和性能&#xff0c;同时也影响着电子产品的可靠性和稳定性。 一般我们常见的铜厚有17.5um&#xff08;0.5oz&#xff09;&#x…

SpringBootWeb案例-准备工作

目录 前言 准备工作 需求&环境搭建 需求 环境搭建 开发规范 Restful开发规范 统一的响应结果 开发流程 前言 根据过往的文章可以知道目前我已经学习完了前端、后端、数据库的基础知识&#xff0c;接下来通过一个基于SpringBoot工程开发的web项目案例。 准备工作 …

来讲一讲面试必问的异步FIFO设计!

异步FIFO设计可以说是数字IC设计工程师面试时必问的一个问题了&#xff0c;也是我们经常使用但是又往往被忽略的一个东西&#xff0c;今天就展开详细说一说不同深度&#xff08;2^N或者非2^N&#xff09;异步FIFO的设计思想&#xff1b; 一&#xff1a;2^N深度异步FIFO设计 1…

Unity开发笔记:截取指定位置含有UI的场景截图并输出

学习记录整理&#xff0c;自用&#xff0c;也希望能帮助到有相同需求的人。 如果直接截全图&#xff1a; string screenshotName "Assets/Textures/UI/20230803/2.png";ScreenCapture.CaptureScreenshot(screenshotName);截取指定位置含有UI的场景截图&#xff1a; …