java 之 继承与多态的详细介绍

在这里插入图片描述

文章目录

  • 类的继承
      • 1. 基本语法
      • 2. 继承的特点
      • 3. 方法的重写(方法的覆盖)
      • super 关键字
      • 1. 调用父类的构造器
      • 2. 访问父类的成员变量
      • 3. 调用父类的方法
      • 4. 在构造器中调用父类方法
      • 封装性以及访问修饰符
      • 抽象方法
      • 1. 声明抽象类
      • 2. 抽象方法
      • 3. 继承抽象类
      • 4. 抽象类的实例化
      • 5. 构造器和抽象类
      • 6. 抽象类 vs 接口
      • 子类对象与父类对象的转换
      • 1. 向上转型(Upcasting)[自动转换]
      • 2. 向下转型(Downcasting)[强制转换]
        • 差异
          • 1. `Animal myAnimal = new Dog();`
          • 2. `Dog myAnimal = new Dog();`
          • 总结
      • instanceof 运算符
      • 语法
      • 示例
      • 应用场景
      • 多态与重载

类的继承

在Java中,类的继承是一种重要的面向对象编程(OOP)概念,它允许一个类(子类)继承另一个类(父类)的属性和方法。这种机制使得代码可以更加灵活、可复用,并支持多层次的类之间的关系。以下是关于Java中类的继承的详细介绍:

1. 基本语法

在Java中,使用关键字 extends 实现类的继承。语法如下:

class Subclass extends Superclass {// 子类的成员变量和方法
}

其中,Subclass 是子类,Superclass 是父类。

2. 继承的特点

  • 单一继承: Java不支持多继承,一个子类只能继承一个父类。这是为了避免多继承可能引发的复杂性和歧义。

  • 构造器的继承: 子类会继承父类的构造器,但是子类的构造器不能直接调用父类的构造器。在子类的构造器中,可以使用 super 关键字调用父类的构造器。

  • 访问权限: 子类可以访问父类中的公有(public)和受保护(protected)的成员,但不能访问私有(private)的成员。

3. 方法的重写(方法的覆盖)

子类可以重写(override)父类中的方法,以满足子类的需求。重写的方法必须具有相同的方法签名(方法名字,参数列表、返回类型),而且访问权限不能比父类中的方法更严格。

class Superclass {void display() {System.out.println("Superclass display");}
}class Subclass extends Superclass {@Overridevoid display() {System.out.println("Subclass display");}
}
  • 注意父类中的private 方法不能被被覆盖,父类中的static 方法能被继承,不能被覆盖

super 关键字

在Java中,super 是一个关键字,用于引用父类的成员变量、方法或构造器。它可以用于以下几种情况:

1. 调用父类的构造器

在子类的构造器中,使用 super 调用父类的构造器。这通常用于在子类的构造过程中执行一些父类的初始化操作。

class Superclass {Superclass(int x) {// 父类构造器}
}class Subclass extends Superclass {Subclass(int x, int y) {super(x); // 调用父类的构造器// 子类构造器}
}

2. 访问父类的成员变量

使用 super 关键字可以在子类中访问父类中的成员变量,尤其是当子类和父类有同名的成员变量时。

class Superclass {int x = 10;
}class Subclass extends Superclass {void display() {System.out.println(super.x); // 访问父类的成员变量}
}

3. 调用父类的方法

在子类中,可以使用 super 关键字调用父类的方法。这在子类重写父类方法的时候很有用,可以在子类方法中调用父类版本的方法。

class Superclass {void display() {System.out.println("Superclass display");}
}class Subclass extends Superclass {@Overridevoid display() {super.display(); // 调用父类的display方法System.out.println("Subclass display");}
}

4. 在构造器中调用父类方法

在子类的构造器中,可以使用 super 调用父类的方法,确保在子类对象初始化时执行必要的父类操作。

class Superclass {void init() {// 父类初始化操作}
}class Subclass extends Superclass {Subclass() {super(); // 调用父类的构造器super.init(); // 调用父类的方法// 子类构造器}
}

总的来说,super 关键字提供了一种访问父类成员的途径,可以在子类中调用父类的构造器、成员变量和方法,从而实现更灵活的代码编写。

封装性以及访问修饰符

Java中封装性的实现主要靠包的实现以及类以及类的成员的访问修饰符来实现
在这里插入图片描述

封装的目的是将对象的状态(成员变量)和行为(方法)封装在一起,提供一种受控的访问机制,防止外部直接访问对象的内部细节。在Java中,封装通过以下方式实现:

  1. 成员变量私有化(Private Fields): 将类的成员变量声明为私有,只能在类的内部访问。

    public class MyClass {private int myField;public int getMyField() {return myField;}public void setMyField(int value) {// 可以在setter方法中添加一些逻辑,例如范围检查if (value >= 0) {myField = value;}}
    }
    
  2. 提供公共方法(Public Methods): 通过公共方法来访问和修改私有成员变量,以实现对成员变量的控制和封装。

    MyClass obj = new MyClass();
    obj.setMyField(42);
    int value = obj.getMyField();
    

通过这种方式,封装隐藏了对象的内部细节,使得对象更加安全、可维护,同时提供了一种更灵活的方式来管理对象的状态。

Java提供了几种访问修饰符,用于控制类、变量、方法等成员的访问权限。

  1. public(公共): 修饰的成员对所有类可见,无访问限制。

  2. private(私有): 修饰的成员只能在当前类中访问,其他类无法直接访问。

  3. protected(受保护): 修饰的成员对同一包内的类和所有子类可见,但对其他包中的类不可见。

  4. default(默认,无修饰符): 修饰的成员对同一包内的类可见,但对其他包中的类不可见。在没有显式声明修饰符的情况下,默认为包内可见。

  5. final(最终): 用于修饰类、方法、变量。修饰类时,表示该类不能被继承;修饰方法时,表示方法不能被重写;修饰变量时,表示变量为常量,不可被修改。

使用访问修饰符和封装的概念,可以控制对象的访问权限,提高代码的安全性和可维护性。

抽象方法

在Java中,抽象类是一种不能被实例化的类,用于定义一些抽象的方法,这些方法在具体的子类中被实现。抽象类通过关键字 abstract 来声明。以下是关于Java抽象类的一些重要概念和规则:

1. 声明抽象类

使用 abstract 关键字来声明抽象类。抽象类可以包含抽象方法和非抽象方法。

abstract class Shape {// 抽象方法abstract void draw();// 非抽象方法void display() {System.out.println("Displaying shape");}
}

2. 抽象方法

抽象方法是没有具体实现的方法,它只有方法签名而没有方法体。任何包含抽象方法的类必须被声明为抽象类。

abstract class Animal {abstract void makeSound();
}

3. 继承抽象类

如果一个类继承了一个抽象类,它必须实现父类中所有的抽象方法,否则这个类也必须声明为抽象类。

class Circle extends Shape {// 实现抽象方法void draw() {System.out.println("Drawing circle");}
}

4. 抽象类的实例化

抽象类不能被实例化,但可以通过创建其非抽象子类的实例来使用抽象类。例如:

Shape shape = new Circle();
shape.draw();     // 调用子类实现的抽象方法
shape.display();  // 调用抽象类中的非抽象方法

5. 构造器和抽象类

抽象类可以有构造器,但它不能被直接实例化。构造器通常被子类调用,以初始化抽象类中的成员变量。

abstract class AbstractClass {AbstractClass() {// 构造器}
}

6. 抽象类 vs 接口

抽象类和接口都是实现代码重用和多态性的机制,但它们有一些区别。主要的区别在于:

  • 抽象类可以包含非抽象方法,而接口中的方法都是抽象的。
  • 类只能继承一个抽象类,但可以实现多个接口。
abstract class AbstractClass {abstract void method1();void method2() {// 非抽象方法}
}interface MyInterface {void method1();void method3();
}

抽象类在设计一些具有共同特征的类时非常有用,而接口更适用于定义一些类似于协议的东西,可以被多个类实现。选择抽象类还是接口取决于具体的设计需求。

子类对象与父类对象的转换

在Java中,子类对象与父类对象之间的转换通常涉及向上转型和向下转型,这是基于类的继承关系的一种操作。

1. 向上转型(Upcasting)[自动转换]

向上转型是将子类对象引用赋给父类对象引用的过程,这是一种隐式的转换,不需要显式的类型转换。向上转型是安全的,因为子类对象可以被视为父类对象。

class Animal {// ...
}class Dog extends Animal {// ...
}Dog myDog = new Dog();
Animal animal = myDog; // 向上转型

在这个例子中,myDogDog 类的对象,通过向上转型,可以将它赋给 Animal 类型的引用变量 animal

2. 向下转型(Downcasting)[强制转换]

向下转型是将父类对象引用转换为子类对象引用的过程,这需要使用显式的类型转换,并且在进行转换之前需要确保原始对象是目标子类的实例。

Animal animal = new Dog();
Dog myDog = (Dog) animal; // 向下转型

在这个例子中,animalAnimal 类的对象,通过向下转型,将其转换为 Dog 类型的引用变量 myDog。需要注意,如果在运行时 animal 不是 Dog 类型的对象,将会抛出 ClassCastException 异常。因此,在进行向下转型之前,通常应当使用 instanceof 运算符来检查对象的类型。

if (animal instanceof Dog) {Dog myDog = (Dog) animal; // 向下转型
}

向上转型和向下转型的操作在处理多态性和继承关系时是常见的,但需要谨慎使用,以确保类型转换的安全性。

差异

这两行代码涉及到Java中的多态性和引用类型的概念。让我们逐一解释这两行代码的区别:

1. Animal myAnimal = new Dog();

这是一个典型的向上转型(Upcasting)的例子。在这里,创建了一个 Dog 类的对象,并将其赋给了一个 Animal 类型的引用变量 myAnimal

这种向上转型的效果是,尽管 myAnimal 的静态类型(声明类型)是 Animal,但在运行时,它引用的是一个 Dog 对象。这使得你可以通过 myAnimal 调用 Animal 类中定义的方法,但不能调用 Dog 类中独有的方法,除非进行强制类型转换。

Animal myAnimal = new Dog();
myAnimal.someMethod();  // 可以调用 Animal 类的方法
// myAnimal.bark();  // 不能调用 Dog 类的方法,因为其静态类型是 Animal
2. Dog myAnimal = new Dog();

这是一个直接创建 Dog 类的对象,并将其赋给了一个 Dog 类型的引用变量 myAnimal。这是一个常规的对象创建和引用赋值的操作。

在这种情况下,myAnimal 的静态类型和运行时类型都是 Dog。因此,你可以直接调用 Dog 类中定义的方法。

Dog myAnimal = new Dog();
myAnimal.someMethod();  // 可以调用 Animal 类的方法
myAnimal.bark();       // 可以调用 Dog 类的方法
总结
  1. Animal myAnimal = new Dog(); 表示使用 Animal 类型的引用指向 Dog 类型的对象,发生了向上转型。
  2. Dog myAnimal = new Dog(); 表示使用 Dog 类型的引用指向 Dog 类型的对象。

在实际应用中,选择使用哪种方式主要取决于代码的设计需求。向上转型通常用于提高代码的灵活性,而直接使用具体类型的引用则可能更加直观和明确。

instanceof 运算符

instanceof 是Java中的一个二元运算符,用于在运行时检查对象是否是特定类的实例,或者是否实现了特定的接口。它返回一个布尔值,表示对象是否是指定类型的实例。

语法

object instanceof type

其中,object 是要检查的对象,type 是要检查的类或接口的类型。

示例

class Animal {// ...
}class Dog extends Animal {// ...
}class Cat extends Animal {// ...
}Animal myAnimal = new Dog();if (myAnimal instanceof Dog) {System.out.println("myAnimal is an instance of Dog");
} else if (myAnimal instanceof Cat) {System.out.println("myAnimal is an instance of Cat");
} else {System.out.println("myAnimal is not an instance of Dog or Cat");
}

在这个例子中,myAnimalAnimal 类型的引用,但它指向的是 Dog 类的实例。通过使用 instanceof 运算符,我们可以在运行时检查 myAnimal 是否是 Dog 类或 Cat 类的实例。

应用场景

  1. 类型检查: 用于检查对象是否属于特定的类或接口。

    if (myObject instanceof MyClass) {// 执行特定的逻辑
    }
    
  2. 避免 ClassCastException: 在进行向下转型时,先使用 instanceof 进行类型检查,以确保对象是目标类型的实例,避免抛出 ClassCastException 异常。

    if (myObject instanceof Dog) {Dog myDog = (Dog) myObject; // 向下转型// 执行特定的逻辑
    }
    

instanceof 在面向对象的程序设计中是一个非常有用的工具,能够增加程序的灵活性和鲁棒性,避免在运行时发生类型不匹配的错误。

多态与重载

多态和重载是两个不同的概念。

  1. 多态性(Polymorphism): 多态是指同一个方法调用可以根据对象的不同类型而具有不同的行为。它主要通过方法的’重写(override)‘实现以及方法重载,使得子类能够提供对方法的自定义实现。多态性通过继承和接口的方式来体现,能够提高代码的灵活性和可扩展性。

    class Animal {void makeSound() {System.out.println("Some generic sound");}
    }class Dog extends Animal {@Overridevoid makeSound() {System.out.println("Bark");}
    }class Cat extends Animal {@Overridevoid makeSound() {System.out.println("Meow");}
    }Animal myDog = new Dog();
    Animal myCat = new Cat();myDog.makeSound();  // 调用 Dog 类的 makeSound 方法
    myCat.makeSound();  // 调用 Cat 类的 makeSound 方法
    
  2. 重载(Overloading): 重载是指在同一个类中,可以定义多个方法,它们具有相同的名称但是参数列表不同。重载通过方法的参数类型、参数个数或者参数顺序的不同来区分不同的方法。

    class Calculator {int add(int a, int b) {return a + b;}double add(double a, double b) {return a + b;}
    }Calculator myCalculator = new Calculator();
    int resultInt = myCalculator.add(3, 5);        // 调用 int add(int a, int b)
    double resultDouble = myCalculator.add(3.0, 5.0);  // 调用 double add(double a, double b)
    

总结:

  • 多态性是面向对象编程中的一个概念,与继承和接口有关,通过方法的重写与重载实现。
  • 重载是指在同一个类中定义多个方法,它们有相同的名称但参数列表不同,通过参数的类型、个数或者顺序的不同来区分。

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

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

相关文章

智能指针及强相关知识经验总结 --- 移动语义、引用计数、循环引用、move()、自定义删除器等

目录 前言 一、shared_ptr 1. 基本用法和构造方法 2. 引用计数机制 3. weak_ptr 解决循环引用 二、unique_ptr 1. 基本用法和构造方法 2. 独占性 3. 所有权转移 1)unique_ptr :: release() 2)移动语义 和 move() 三、 对比 shared_ptr 和 un…

Linux中项目部署步骤

安装jdk,tomcat 安装步骤 1,将压缩包,拷贝到虚拟机中。 通过工具,将文件直接拖到虚拟机的/home下 2,回到虚拟机中,查看/home下,有两个压缩文件 3,给压缩文件做解压缩操作 tar -z…

Hive数据倾斜之:数据类型不一致导致的笛卡尔积

Hive数据倾斜之:数据类型不一致导致的笛卡尔积 目录 Hive数据倾斜之:数据类型不一致导致的笛卡尔积一、问题描述二、原因分析三、精度损失四、问题解决 一、问题描述 如果两张表的jion,关联键分布较均匀,没有明显的热点问题&…

计算机基础知识64

ForeignKey属性 to:设置要关联的表 related_name: 反向操作时,使用的字段名,用于代替原反向查询时的’表名_set’ related_query_name:反向查询操作时,使用的连接前缀,用于替换表名 to_field:设置要关联的表…

最长连续序列(leetcode 128)

文章目录 1.问题描述2.难度等级3.热门指数4.解题思路方法一:排序方法二:哈希表 5.实现示例参考文献 1.问题描述 给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。 请你…

【华为OD题库-049】评论转换输出-java

题目 在一个博客网站上,每篇博客都有评论。每一条评论都是一个非空英文字母字符串。评论具有树状结构,除了根评论外,每个评论都有一个父评论。 当评论保存时,使用以下格式: 首先是评论的内容; 然后是回复当前评论的数量。 最后是当…

如何保持操纵机构丝杆的精度?

滚珠丝杆是操纵机构中的重要组成部分,可以传递较高的扭矩,并且具有低摩擦、高效率和快速响应的特性,这使得操纵机构能够实现高速、高精度的运动控制,这对于整个系统的性能和精度具有决定性的影响,保持操纵机构丝杆的精…

互联网Java工程师面试题·Spring Boot篇·第二弹

目录 8、什么是 YAML? 9、如何实现 Spring Boot 应用程序的安全性? 10、如何集成 Spring Boot 和 ActiveMQ? 11、如何使用 Spring Boot 实现分页和排序? 12、什么是 Swagger?你用 Spring Boot 实现了它吗? …

YoloV5改进策略:Swift Parameter-free Attention,无参注意力机制,超分模型的完美迁移

摘要 https://arxiv.org/pdf/2311.12770.pdf https://github.com/hongyuanyu/SPAN SPAN是一种超分网络模型。SPAN模型通过使用参数自由的注意力机制来提高SISR的性能。这种注意力机制能够增强重要信息并减少冗余,从而在图像超分辨率过程中提高图像质量。 具体来说,SPAN模…

【wvp】测试记录

ffmpeg 这是个莫名其妙的报错,通过排查,应该是zlm哪个进程引起的 会议室的性能 网络IO也就20M

全志T527设置gpio口输出高电平实际输出低电平

前言 在调试T527的时候,主板另外添加了gpio口去控制usb口的电源开关,软件上面需要在内核运行的时候将gpio口设置输出高电平,usb口才可以正常使用。改好系统固件后,升级发现,机器开机动画过程中可以控制gpio口去打开us…

ArkUI组件--Button组件

1.声明Button组件 Button(label?:ResourceStr) #label是按钮上显示的文本 ①label是文字类型 所写文字会在按钮上显示 ②不输入label内容,需要额外定义一些描述。例如插入图片(需要定义图片属性) Button(){Image($r(app.media.xxx)).wi…

【题目】栈和队列专题

文章目录 专题一:栈系列1. 中缀表达式转后缀表达式(逆波兰式)2. 有效的括号3. 用栈实现队列4. 最小栈 专题一:栈系列 1. 中缀表达式转后缀表达式(逆波兰式) 算法原理 2. 有效的括号 题目链接 算法原理 代…

SpringBoot-监听Nacos动态修改日志级别

目录 一、pom文件 二、项目配置文件 三、日志配置文件 四、日志监听类 五、日志动态修改服务类 线上系统的日志级别一般都是 INFO 级别,有时候需要查看 WARN 级别的日志,所以需要动态修改日志级别。微服务项目中使用 Nacos 作为注册中心&#xff0c…

C++面试宝典第2题:逆序输出整数

题目 写一个方法,将一个整数逆序打印输出到控制台。注意:当输入的数字含有结尾的0时,输出不应带有前导的0。比如:123的逆序输出为321,8600的逆序输出为68,-609的逆序输出为-906。 解析 这道题本身并没有什么…

Java架构师技术架构路线

目录 1 概论2 如何规划短中长期的技术架构路线图3 如何规划面向未来的架构4 如何修订路线图执行过程中的偏差5 如何落地路线图-阿里系糙快猛之下的敏捷模式想学习架构师构建流程请跳转:Java架构师系统架构设计 1 概论 首先,规划一个短中长期的技术路线图是非常重要的。短中…

java SSM毕业生信息管理myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

前言 学校的规模不断扩大,学生数量急剧增加,有关学生的各种信息量也成倍增长。面对庞大的信息量需要有学生信息管理系统来提高学生管理工作的效率。通过这样的系统可以做到信息的规范管理、科学统计和快速查询、修改、增加、删除等,从而减少管…

lv11 嵌入式开发 RTC 17

目录 1 RTC简介 ​编辑2 Exynos4412下的RTC控制器 2.1 概述 2.2 特征 2.3 功能框图 3 寄存器介绍 3.1 概述 3.2 BCD格式的年月日寄存器 3.3 INTP中断挂起寄存器 3.4 RTCCON控制寄存器 3.5 CURTICCNT 作为嘀嗒定时器使用的寄存器 4 RTC编程 5 练习 1 RTC简介 RTC(…

关于优雅的使用SQL多行转多列的记录(doris)

文章目录 应用需求场景记录过程1. 准备数据2. 给数据根据姓名分组,加上序号.3. 根据name分组成map结构4. 拆分map 应用需求场景 准备的数据是这样的: 需要将每个人的成绩显示在一行上,需要的结果如下,但是我的情况是课程有非常…

联想LJ2655DN激光打印机清零方法

随着打印机的使用越来越频繁,需要更换耗材的时候也越来越多;但是更换上新的耗材后,很多用户都会遇到一个问题,就是更换完新的耗材后打印机仍然提示寿命将近,或者无墨粉盒灯情况,这个时候就需要我们对打印机…