封装,继承,多态(续)

news2025/4/18 7:31:58

在Java中,最基础的三原则无疑是封装,继承,多态

对于这三类,最基本同样最重要,我们是会经常遇到的,在编程中,会使用,但在考试中还有一定的不理解。

对于这点,我在这里进行汇总

一.封装的三个步骤

在 Java 中,封装的三个步骤也类似,但 Java 的语法和机制与 Python 有所不同。以下是 Java 中封装的三个步骤:

1. 定义类

封装的第一步是定义一个类,类是封装的载体,它将数据(属性)和行为(方法)组织在一起。

例如,定义一个“学生”类:

 

public class Student {
    private String name;  // 属性
    private int age;      // 属性

    // 构造方法
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 方法
    public void study() {
        System.out.println(name + " is studying.");
    }
}

在这个例子中,Student 类定义了学生的基本属性(nameage)和行为(study 方法)。

2. 将数据隐藏在类的内部

封装的第二步是将类的内部数据(属性)隐藏起来,通常通过将属性设置为私有属性(使用 private 关键字)。这样,外部代码无法直接访问这些属性,只能通过类提供的方法来操作它们。例如:

public class Student {
    private String name;  // 私有属性
    private int age;      // 私有属性

    // 构造方法
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 获取 name 属性的值
    public String getName() {
        return name;
    }

    // 设置 name 属性的值
    public void setName(String name) {
        this.name = name;
    }

    // 获取 age 属性的值
    public int getAge() {
        return age;
    }

    // 设置 age 属性的值
    public void setAge(int age) {
        if (age > 0) {
            this.age = age;
        } else {
            System.out.println("Invalid age.");
        }
    }

    // 方法
    public void study() {
        System.out.println(name + " is studying.");
    }
}

在这个例子中,nameage 是私有属性,外部代码无法直接访问它们,只能通过 getNamesetNamegetAgesetAge 这些方法来获取和设置它们的值。这样可以防止外部代码直接修改属性值,从而保证数据的安全性和一致性。

3. 提供公共接口

封装的第三步是为类提供公共接口(即公共方法),这些方法允许外部代码通过这些接口与类的内部数据进行交互,但隐藏了具体的实现细节。例如:

public class Student {
    private String name;  // 私有属性
    private int age;      // 私有属性

    // 构造方法
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 获取 name 属性的值
    public String getName() {
        return name;
    }

    // 设置 name 属性的值
    public void setName(String name) {
        this.name = name;
    }

    // 获取 age 属性的值
    public int getAge() {
        return age;
    }

    // 设置 age 属性的值
    public void setAge(int age) {
        if (age > 0) {
            this.age = age;
        } else {
            System.out.println("Invalid age.");
        }
    }

    // 方法
    public void study() {
        System.out.println(name + " is studying.");
    }
}

在这个例子中,getNamesetNamegetAgesetAge 是公共方法,它们允许外部代码通过这些方法访问和修改私有属性的值,但隐藏了属性的直接访问。study 方法也是一个公共方法,它定义了学生的行为。

使用封装的类

在其他类中,可以通过创建 Student 类的对象来使用封装的方法:

public class Main {
    public static void main(String[] args) {
        Student student = new Student("Alice", 20);
        student.study();  // 调用方法

        System.out.println("Name: " + student.getName());  // 获取属性值
        student.setName("Bob");  // 设置属性值
        System.out.println("New Name: " + student.getName());
    }
}

通过这种方式,Java 的封装机制既保证了数据的安全性,又提供了灵活的操作接口。

二.继承

1. 继承的基本语法

在 Java 中,使用 extends 关键字来实现继承。子类继承父类后,可以访问父类的非私有属性和方法。

示例:
// 父类
class Animal {
    String name;

    public Animal(String name) {
        this.name = name;
    }

    public void speak() {
        System.out.println(name + " makes a sound.");
    }
}

// 子类
class Dog extends Animal {
    public Dog(String name) {
        super(name); // 调用父类的构造方法
    }

    @Override
    public void speak() {
        System.out.println(name + " barks.");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myAnimal = new Animal("Generic Animal");
        myAnimal.speak(); // 输出:Generic Animal makes a sound.

        Dog myDog = new Dog("Buddy");
        myDog.speak(); // 输出:Buddy barks.
    }
}

2. 继承的特点

  • 代码复用:子类继承父类后,可以直接使用父类的非私有属性和方法,减少代码重复。

  • 扩展性:子类可以在继承父类的基础上,添加新的属性和方法,或者重写父类的方法以实现特定的行为。

  • 层次结构:继承可以形成类的层次结构,子类可以继承父类的属性和方法,父类可以作为多个子类的共同基类。

3. 构造方法和继承

  • 父类构造方法的调用:子类的构造方法中必须显式或隐式地调用父类的构造方法。如果父类有无参构造方法,则子类构造方法中可以省略 super() 调用;否则必须显式调用父类的构造方法。

  • super 关键字:用于访问父类的属性和方法,也可以在子类的构造方法中调用父类的构造方法。

示例:
class Animal {
    String name;

    public Animal(String name) {
        this.name = name;
    }
}

class Dog extends Animal {
    public Dog(String name) {
        super(name); // 调用父类的构造方法
    }
}

4. 方法重写(Override)

子类可以重写父类的方法,以实现特定的行为。重写的方法必须与父类的方法具有相同的方法名、参数列表和返回值类型。

示例:
class Animal {
    public void speak() {
        System.out.println("Animal speaks.");
    }
}

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

5. 方法重载(Overload)

子类可以重载父类的方法,即在子类中定义多个同名方法,但参数列表不同。

示例:
class Animal {
    public void speak() {
        System.out.println("Animal speaks.");
    }
}

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

    public void speak(String language) {
        System.out.println("Dog barks in " + language);
    }
}

6. 访问修饰符和继承

  • public:父类中被声明为 public 的属性和方法可以在子类中访问。

  • protected:父类中被声明为 protected 的属性和方法可以在子类中访问,也可以在同一个包中的其他类中访问。

  • private:父类中被声明为 private 的属性和方法不能被子类直接访问,但可以通过父类提供的公共方法间接访问。

  • 默认访问权限(无修饰符):父类中没有访问修饰符的属性和方法只能在同一个包中的类中访问。

7. 继承的限制

  • Java 不支持多继承:一个类只能继承一个父类,但可以通过接口实现类似多继承的效果。

  • 构造方法不能被继承:子类不能继承父类的构造方法,但可以通过 super() 调用父类的构造方法。

  • final 类和方法不能被继承或重写:如果一个类被声明为 final,则不能被继承;如果一个方法被声明为 final,则不能被子类重写。

8. 继承的使用场景

  • 通用行为的抽象:父类可以定义通用的行为,子类可以继承并扩展这些行为。

  • 代码复用:子类可以复用父类的代码,减少重复代码。

  • 多态的实现:通过继承,可以实现运行时多态,即通过父类引用调用子类的方法。

9. 继承的优缺点

  • 优点

    • 代码复用:减少重复代码。

    • 扩展性:子类可以扩展父类的功能。

    • 层次结构清晰:形成类的层次结构,便于理解和维护。

  • 缺点

    • 耦合性高:子类与父类之间存在较强的依赖关系,父类的修改可能影响子类。

    • 过度继承可能导致复杂性增加:过多的继承层次可能导致代码难以理解和维护。

总结

继承是面向对象编程中的一个重要特性,它允许子类继承父类的属性和方法,从而实现代码复用和功能扩展。通过合理使用继承,可以提高代码的可维护性和可扩展性。然而,过度使用继承可能导致代码耦合度过高,因此需要谨慎设计类的层次结构。

三.多态

多态在之前的博客中也描述过了

现在简要描写的是多态中重写与重载的使用,我相信不少人会把这两点给搞混,现在我来进行描述,帮助大家区分一下

多态(Polymorphism)是面向对象编程中的一个重要概念,它允许使用一个统一的接口来处理不同类型的对象,从而实现代码的通用性和灵活性。多态的核心在于“一个接口,多种实现”,即同一个接口可以被不同的子类实现,而调用代码不需要关心具体的实现细节。

在 Java 中,多态主要通过继承接口来实现,具体包括编译时多态运行时多态

1. 编译时多态(静态多态)

编译时多态主要通过**方法重载(Overloading)**实现。方法重载允许在同一个类中定义多个同名方法,但这些方法的参数列表必须不同(参数类型、参数个数或二者都不同)。编译器根据方法的参数列表来决定调用哪个方法。

示例:
class Calculator {
    public int add(int a, int b) {
        System.out.println("Adding two integers");
        return a + b;
    }

    public double add(double a, double b) {
        System.out.println("Adding two doubles");
        return a + b;
    }

    public int add(int a, int b, int c) {
        System.out.println("Adding three integers");
        return a + b + c;
    }
}

public class Main {
    public static void main(String[] args) {
        Calculator calc = new Calculator();
        calc.add(1, 2);          // 调用第一个 add 方法
        calc.add(1.5, 2.5);      // 调用第二个 add 方法
        calc.add(1, 2, 3);       // 调用第三个 add 方法
    }
}

在编译时,Java 编译器会根据方法的参数列表来确定调用哪个 add 方法。这种多态是静态的,因为方法的绑定是在编译时完成的。

2. 运行时多态(动态多态)

运行时多态主要通过方法重写(Overriding)接口实现来实现。运行时多态的核心是父类引用指向子类对象,调用方法时,实际执行的是子类的实现。这种多态是动态的,因为方法的绑定是在运行时完成的。

方法重写实现运行时多态

当子类重写了父类的方法时,通过父类引用调用该方法时,实际执行的是子类的实现。

示例:
class Animal {
    public void speak() {
        System.out.println("Animal speaks");
    }
}

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

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

public class Main {
    public static void main(String[] args) {
        Animal myDog = new Dog();
        myDog.speak();  // 输出:Dog barks

        Animal myCat = new Cat();
        myCat.speak();  // 输出:Cat meows
    }
}

在这个例子中:

  • Animal 是父类,DogCat 是子类。

  • DogCat 都重写了 speak 方法。

  • main 方法中,myDogmyCatAnimal 类型的引用,但它们分别指向了 DogCat 的对象。

  • 调用 speak 方法时,实际执行的是子类的实现,而不是父类的实现。这种行为称为动态绑定运行时多态

接口实现实现运行时多态

接口是 Java 中实现多态的另一种方式。通过接口,不同的类可以实现同一个接口,并提供不同的实现。

示例:
interface Animal {
    void speak();
}

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

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

public class Main {
    public static void main(String[] args) {
        Animal myDog = new Dog();
        myDog.speak();  // 输出:Dog barks

        Animal myCat = new Cat();
        myCat.speak();  // 输出:Cat meows
    }
}

在这个例子中:

  • Animal 是一个接口,DogCat 都实现了 Animal 接口。

  • myDogmyCatAnimal 类型的引用,但它们分别指向了 DogCat 的对象。

  • 调用 speak 方法时,实际执行的是具体实现类的方法。

3. 多态的好处

  • 代码复用性:通过父类引用或接口引用,可以编写通用的代码,减少重复代码。

  • 扩展性:新增子类时,无需修改现有代码,只需实现父类或接口即可。

  • 灵活性:调用代码不需要关心具体的实现细节,只需通过统一的接口调用方法。

4. 多态的实现条件

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

  1. 继承:子类继承父类。

  2. 方法重写:子类重写父类的方法。

  3. 父类引用指向子类对象:通过父类引用调用方法时,实际执行的是子类的实现。

5. 注意事项

  • 静态方法和私有方法不能被重写:因此它们不能参与运行时多态。

  • 构造方法不能被重写:因此构造方法也不能参与多态。

  • 访问修饰符的限制:子类重写的方法不能比父类方法的访问权限更严格。

总结

多态是面向对象编程的核心特性之一,它通过方法重载和方法重写实现了编译时多态和运行时多态。运行时多态是多态的核心,它允许通过父类引用调用子类的方法,从而实现代码的通用性和灵活性。

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

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

相关文章

Java excel导入/导出导致内存溢出问题,以及解决方案

excel导入/导出导致内存溢出问题,以及解决方案 1、内存溢出问题导入功能重新修正,采用SAX的流式解析数据。并结合业务流程。导出功能:由于精细化了业务流程,导致比较代码比较冗杂,就只放出最简单的案例。 1、内存溢出问…

10 个最新 CSS 功能已在所有主流浏览器中得到支持

前言 CSS 不断发展,新功能使我们的工作更快、更简洁、更强大。得益于最新的浏览器改进(Baseline 2024),许多新功能现在可在所有主要引擎上使用。以下是您可以立即开始使用的10 CSS新功能。 1. Scrollbar-Gutter 和 Scrollbar-Co…

思科模拟器的单臂路由,交换机,路由器,路由器只要两个端口的话,连接三台电脑该怎么办,划分VLAN,dotlq协议

单臂路由 1. 需求:让三台电脑互通 2. 在二层交换机划分vlan,并加入; 3. 将连接二层交换机和路由器的端口f0/4改为trunk模式 4. 路由器:进入连接路由器的f0/0端口将端口开启 5. 进入每个vlan设dotlq协议并设网络IP&#xff08…

14 nginx 的 dns 缓存的流程

前言 这个是 2020年11月 记录的这个关于 nginx 的 dns 缓存的问题 docker 环境下面 前端A连到后端B 前端B连到后端A 最近从草稿箱发布这个问题的时候, 重新看了一下 发现该问题的记录中仅仅是 定位到了 nginx 这边的 dns 缓存的问题, 但是 并没有到细节, 没有到 具体的 n种…

实战教程:使用JetBrians Rider快速部署与调试PS5和Xbox上的UE项目

面向主机游戏开发者的重大新闻!在2024.3版本中,JetBrains Rider 增加了对 PlayStation5 和 Xbox 游戏主机的支持,您可以直接在您喜欢的游戏主机上构建、部署和调试 Unreal Engine 和自定义游戏引擎。 JetBrains Rider现在支持主机游戏开发&am…

专题十五:动态路由——BGP

一、BGP的基本概念 BGP(Border Gateway Protocol,边界网关协议)是一种用于在不同自治系统(AS)之间交换路由信息的外部网关协议(EGP)。通过TCP179端口建立连接。目前采用BGP4版本,IP…

hive数仓要点总结

1.OLTP和OLAP区别 OLTP(On-Line Transaction Processing)即联机事务处理,也称为面向交易的处理过程,其基本特征是前台接收的用户数据可以立即传送到计算中心进行处理,并在很短的时间内给出处理结果,是对用…

git安装(windows)

通过网盘分享的文件:资料(1) 链接: https://pan.baidu.com/s/1MAenYzcQ436MlKbIYQidoQ 提取码: evu6 点击next 可修改安装路径 默认就行 一般从命令行调用,所以不用创建。 用vscode,所以这么选择。

微信小程序实战案例 - 餐馆点餐系统 阶段1 - 菜单浏览

阶段 1 – 菜单浏览(超详细版) 目标:完成「首页=菜品卡片列表」 打好 UI 地基会从 云数据库 拉取 categories / dishes 并渲染打 Git Tag v1.0‑menu 1. 技术/知识点速览 知识点关键词说明云数据库db.collection().where().…

Dashboard的安装和基本使用

1.Dashboard简介: Dashboard是Kubernetes的Web图形用户界面(GUI),它为用户提供了一个直观的方式来管理和监控Kubernetes集群。 2.实验基础和前置条件: 本实验以Kubernetes集群环境搭建与初始化-CSDN博客为基础和前置…

英语单词 list 11

前言 这一个 list 是一些简单的单词。感觉这个浏览单词的方法比较低效,所以准备每天最多看一个 list ,真要提升英语水平,感觉还是得直接做阅读理解题。就像我们接触中文阅读材料一样,当然光知道这个表面意思还不够,还…

通义灵码助力Neo4J开发:快速上手与智能编码技巧

在 Web 应用开发中,Neo4J 作为一种图数据库,用于存储节点及节点间的关系。当图结构复杂化时,关系型数据库的查找效率会显著降低,甚至无法有效查找,这时 Neo4J 的优势便凸显出来。然而,由于其独特的应用场景…

高性能文件上传服务

高性能文件上传服务 —— 您业务升级的不二选择 在当今互联网数据量激增、文件体积日益庞大的背景下,高效、稳定的文件上传方案显得尤为重要。我们的文件分块上传服务端采用业界领先的 Rust HTTP 框架 Hyperlane 开发,凭借其轻量级、低延时和高并发的特…

Java Lambda 表达式详解:发展史、语法、使用场景及代码示例

Java Lambda 表达式详解:发展史、语法、使用场景及代码示例 1. Lambda 表达式的发展史 背景与动机 JDK 7 前:Java的匿名内部类虽强大,但代码冗余(如事件监听器、集合遍历)。JDK 8(2014)&#…

【从0到1学Elasticsearch】Elasticsearch从入门到精通(下)

我们在【从0到1学Elasticsearch】Elasticsearch从入门到精通(上)这边文章详细讲解了如何创建索引库和文档及javaAPI操作,但是在实战当中,我们还需要根据一些特殊字段对文档进行查找搜索,仅仅靠id查找文档是显然不够的。…

Python实现贪吃蛇二

上篇文章Python实现贪吃蛇一,实现了一个贪吃蛇的基础版本,但存在一些不足,也缺乏一些乐趣。本篇文章将对其进行一些改进,主要修改/实现以下几点: 1、解决食物随机生成的位置与蛇身重合问题 2、蛇身移动加速/减速功能 3…

基于51单片机的正负5V数字电压表( proteus仿真+程序+设计报告+讲解视频)

基于51单片机的正负5V数字电压表( proteus仿真程序设计报告讲解视频) 仿真图proteus7.8及以上 程序编译器:keil 4/keil 5 编程语言:C语言 设计编号:S0101 1. 主要功能: 设计一个基于51单片机数字电压表 1、能够…

Java雪花算法

以下是用Java实现的雪花算法代码示例,包含详细注释和异常处理: 代码下面有解析 public class SnowflakeIdGenerator {// 起始时间戳(2020-01-01 00:00:00)private static final long START_TIMESTAMP 1577836800000L;// 各部分…

前端大屏可视化项目 局部全屏(指定盒子全屏)

需求是这样的&#xff0c;我用的项目是vue admin 项目 现在需要在做大屏项目 不希望显示除了大屏的其他东西 于是想了这个办法 至于大屏适配问题 请看我文章 底部的代码直接复制就可以运行 vue2 px转rem 大屏适配方案 postcss-pxtorem-CSDN博客 <template><div …

01_JDBC

文章目录 一、概述1.1、什么是JDBC1.2、JDBC原理 二、JDBC入门2.1、准备工作2.1.1、建库建表2.1.2、新建项目 2.2、建立连接2.2.1、准备四大参数2.2.2、加载驱动2.2.3、准备SQL语句2.2.4、建立连接2.2.5、常见问题 2.3、获取发送SQL的对象2.4、执行SQL语句2.5、处理结果2.6、释…