【️如何理解面向对象和面向过程】

news2024/12/24 21:38:11

在这里插入图片描述

✅如何理解面向对象和面向过程?

  • 典型理解
  • ✅扩展知识仓
    • ✅面向对象的三大基本特征
      • ✅封装
      • ✅继承
      • ✅多态
  • ✅为什么Java不支持多继承?
    • ✅菱形继承问题
    • ✅Java 8 中的多继承
  • ✅面向对象的五大基本原则?

典型理解


面向过程把问题分解成一个一个步骤,每个步骤用函数实现,依次调用即可。

我们在进行面向过程编程的时候,不需要考虑那么多,上来先定义一个函数,然后使用各种诸如if-else、for-each等方式进行代码执行。最典型的用法就是实现一个简单的算法,比如实现冒泡排序。


面向对象将问题分解成一人一个步骤,对每个步骤进行相应的抽象,形成对象,通过不同对象之间的调用,组合解决问题。

就是说,在进行面向对象进行编程的时候,要把属性、行为等封装成对象,然后基于这些对象及对象的能力进行业务逻辑的实现。比如想要造一辆车,上来要先把车的各种属性定义出来,然后抽象成一个Car类。

面向对象有封装、继承、多态二大基本特征,和单一职责原则、开放封闭原则、Liskov替换原则、依赖倒置原则和 接口隔离原则等五大基本原则。

✅扩展知识仓

✅面向对象的三大基本特征

三大基本特征:封装继承多态

✅封装

**封装就是把现实世界中的客观事物抽象成一个Java类,然后在类中存放属性和方法。**比如:封装一个汽车类,其中包含了发动机、轮胎、底盘等属性,并且有启动、前进等方法。

//定义一个汽车Car类
public class Car {  
    // 私有变量  
    private String brand; // 品牌  
    private String model; // 型号  
    private int year; // 生产年份  
    private String color; // 颜色  
    private double price; // 价格  
    private Engine engine; // 引擎  
    private Transmission transmission; // 变速器  
    private boolean isOwned; // 是否拥有  
      
    // 构造方法  
    public Car(String brand, String model, int year, String color, double price, Engine engine, Transmission transmission) {  
        this.brand = brand;  
        this.model = model;  
        this.year = year;  
        this.color = color;  
        this.price = price;  
        this.engine = engine;  
        this.transmission = transmission;  
        this.isOwned = false;  
    }  
      
    // 公共方法:获取品牌  
    public String getBrand() {  
        return brand;  
    }  
      
    // 公共方法:设置品牌  
    public void setBrand(String brand) {  
        this.brand = brand;  
    }  
      
    // 公共方法:获取型号  
    public String getModel() {  
        return model;  
    }  
      
    // 公共方法:设置型号  
    public void setModel(String model) {  
        this.model = model;  
    }  
      
    // 公共方法:获取生产年份  
    public int getYear() {  
        return year;  
    }  
      
    // 公共方法:设置生产年份  
    public void setYear(int year) {  
        this.year = year;  
    }  
      
    // 公共方法:获取颜色  
    public String getColor() {  
        return color;  
    }  
      
    // 公共方法:设置颜色  
    public void setColor(String color) {  
        this.color = color;  
    }  
      
    // 公共方法:获取价格  
    public double getPrice() {  
        return price;  
    }  
      
    // 公共方法:设置价格  
    public void setPrice(double price) {  
        this.price = price;  
    }  
      
    // 公共方法:获取引擎对象  
    public Engine getEngine() {  
        return engine;  
    }  
      
    // 公共方法:设置引擎对象  
    public void setEngine(Engine engine) {  
        this.engine = engine;  
    }  
      
    // 公共方法:获取变速器对象  
    public Transmission getTransmission() {  
        return transmission;  
    }  
      
    // 公共方法:设置变速器对象  
    public void setTransmission(Transmission transmission) {  
        this.transmission = transmission;  
    }  
      
    // 公共方法:判断是否拥有该汽车,如果拥有则返回true,否则返回false。在构造函数中,isOwned被设置为false,表示初始状态为未拥有。可以在后续操作中改变其状态。  
    public boolean isOwned() {  
        return isOwned;  
    }  
}

✅继承

像现实世界中儿子可以继承父亲的财产、样貌、行为等一样,编程世界中也有继承,继承的主要目的就是为了复用。子类可以继承父类,这样就可以把父类的属性和方法继承过来。

比如:Dog类,可以继承Animal类,继承过来嘴巴,颜色、等属性,吃东西、奔跑等行为。

// Animal类  
public class Animal {  
    private String name;  
      
    public Animal(String name) {  
        this.name = name;  
    }  
      
    public String getName() {  
        return name;  
    }  
      
    public void setName(String name) {  
        this.name = name;  
    }  
      
    // 抽象方法,需要子类实现  
    public abstract void makeSound();  
}  
  
// Dog类,继承自Animal类  
public class Dog extends Animal {  
    private String breed;  
      
    public Dog(String name, String breed) {  
        super(name); // 调用父类的构造函数  
        this.breed = breed;  
    }  
      
    public String getBreed() {  
        return breed;  
    }  
      
    public void setBreed(String breed) {  
        this.breed = breed;  
    }  
      
    // 实现父类的抽象方法  
    @Override  
    public void makeSound() {  
        System.out.println("汪汪!");  
    }  
}

在这个例子中,Animal类是一个抽象类,定义了一个抽象方法makeSound,它需要由子类来实现。Dog类继承了Animal类,并实现了makeSound方法,因此它是一个具体的类。在Dog类中,我们还添加了一个新的属性breed和一个相应的方法来获取和设置该属性的值。

✅多态

多态是指在父类中定义的方法被子类继承之后,可以通过重写,使得父类和子类具有不同的实现,这使得同一个方法在父类极其各个子类中具有不同的含义。

// 定义一个接口,名为Animal  
public interface Animal {  
    // 定义一个抽象方法,用于发出动物的叫声  
    void makeSound();  
}  
  
// 定义一个类,名为Dog,实现Animal接口  
public class Dog implements Animal {  
    // 重写makeSound方法,实现狗的叫声  
    @Override  
    public void makeSound() {  
        System.out.println("汪汪!");  
    }  
}  
  
// 定义一个类,名为Cat,实现Animal接口  
public class Cat implements Animal {  
    // 重写makeSound方法,实现猫的叫声  
    @Override  
    public void makeSound() {  
        System.out.println("喵喵!");  
    }  
}  
  
// 定义一个类,名为Zoo,包含一个Animal类型的成员变量  
public class Zoo {  
    // 定义一个Animal类型的成员变量,可以是任何实现Animal接口的类对象  
    private Animal animal;  
      
    // 构造函数,接受一个Animal类型的参数,用于初始化animal成员变量  
    public Zoo(Animal animal) {  
        this.animal = animal;  
    }  
      
    // 定义一个方法,让动物发出叫声  
    public void letAnimalMakeSound() {  
        // 使用多态性,调用animal对象的makeSound方法,实现不同的叫声  
        animal.makeSound();  
    }  
}  
  
// 在主函数中测试多态性的实现  
public static void main(String[] args) {  
    // 创建一个Dog对象  
    Dog dog = new Dog();  
    // 使用Dog对象创建一个Zoo对象  
    Zoo zoo = new Zoo(dog);  
    // 调用Zoo对象的letAnimalMakeSound方法,让动物发出叫声  
    zoo.letAnimalMakeSound(); // 输出 "汪汪!"  
      
    // 创建一个Cat对象  
    Cat cat = new Cat();  
    // 使用Cat对象创建一个Zoo对象  
    zoo = new Zoo(cat);  
    // 调用Zoo对象的letAnimalMakeSound方法,让动物发出叫声  
    zoo.letAnimalMakeSound(); // 输出 "喵喵!"  
}

在这个例子中,我们定义了一个Animal接口和两个实现了该接口的类Dog和Cat。我们还定义了一个Zoo类,其中包含一个Animal类型的成员变量。在Zoo类中,我们使用多态性来调用Animal对象的makeSound方法,实现了不同的叫声。在主函数中,我们分别使用Dog和Cat对象创建了两个Zoo对象,并调用了它们的letAnimalMakeSound方法,输出了不同的叫声。

✅为什么Java不支持多继承?

因为如果要实现多继承,就会像C++中一样,存在菱形继承的问题,C++为了解决菱形继承问题,又引入了虚继承。因为支持多继承,引入了菱形继承问题,又因为要解决菱形继承问题,引入了虚继承。而经过分析,人们发现我们其实真正想要使用多继承的情况并不多。所以,在Java 中,不允许“多继承”,即一个类不允许继承多个父类。

除了菱形的问题,支持多继承复杂度也会增加。一个类然承了多个父类,可能会继承大量的属性和方法,导致类的接口变得庞大、难以理解和维护。此外,在修改一个父类时,可能会影响到多个子类,增加了代码的耦合度。

在Java 8以前,接口中是不能有方法的实现的。所以一个类同时实现多个接口的话,也不会出现C++中的歧义问题。因为所有方法都没有方法体,真正的实现还是在子类中的。但是,Java 8中支持了默认函数(defaultmethod),即接口中可以定义一个有方法体的方法了。

而又因为Java支持同时实现多个接口,这就相当于通过implements就可以从多人接口中继承到多人方法了,但是,Java8中为了避免菱形继承的问题,在实现的多个接口中如果有相同方法,就会要求该类必须重写这个方法。

✅菱形继承问题

Java的创始人James Gosling曾经回答过,他表示:

"Java之所以不支持一个类继承多个类,主要是因为在设计之初我们听取了来自C++和Obiective-C等阵营的人的意见。因为多继承会产生很多歧义问题。”

Gosling老人家提到的歧义问题,其实是C++因为支持多继承之后带来的菱形继承问题。

假设我们有类B和类C,它们都继承了相同的类A。另外我们还有类D,类D通过多重继承机制继承了类B和类C.。

在这里插入图片描述
这时候,因为D同时继承了B和C,并且B和C又同时继承了A,那么,D中就会因为多重继承,继承到两份来自A中的属性和方法。

这时候,在使用D的时候,如果想要调用一个定义在A中的方法时,就会出现歧义。

因为这样的继承关系的形状类似于菱形,因此这个问题被形象地称为菱形继承问题。

而C++为了解决菱形继承问题,又引入了虚继承

因为支持多继承,引入了菱形继承问题,又因为要解决菱形继承问题,引入了虚继承。而经过分析,人们发现我们其实真正想要使用多继承的情况并不多。

所以,在Java 中,不允许“声明多继承”,即一个类不允许继承多个父类。但是Java 允许“实现多继承”,即个类可以实现多个接口,一个接口也可以继承多个父接口。由于接口只允许有方法声明而不允许有方法实现(Java 8之前),这就避免了 C++ 中多继承的歧义问题。

✅Java 8 中的多继承

Java不支持多继承,但是是支持多实现的,也就是说,同一个类可以同时实现多个接口。

我们知道,在Java 8以前,接口中是不能有方法的实现的。所以一个类同时实现多个接口的话,也不会出现C++中的歧义问题。因为所有方法都没有方法体,真正的实现还是在子类中的。

💡那么问题来了?

Java 8中支持了默认函数 (default method ),即接口中可以定义一个有方法体的方法了。

public interface Pet {
	public default void eat() {
		System.out.println("Pet Is Eating");
	}
}

而又因为Java支持同时实现多个接口,这就相当于通过implements就可以从多个接口中继承到多人方法了,这不就是变相支持了多继承么。

那么,Java是怎么解决菱形继承问题的呢? 我们再定义一个哺乳动物接口,也定义一个eat方法。

public interface Mammal {
	public default void eat() {
		System.out.println("Mammal Is Eating");
	}
}

然后定义一个Cat,让他分别实现两个接口:

public class Cat implements Pet,Mammal {
	
}

这个时间编译会报错:

error: class Cat inherits unrelated defaults for eat() from types Mammal and Pet

这个时候,就要求Cat类中,必须重写eat()。

public class Cat implements Pet,Mammal {
	@Override
	public void eat()  {
		System.out.println("Cat Is Eating");
	}
}

所以可以看到,Java并没有帮我们解决多继承的歧义问题,而是把这个问题留给开发人员,通过重写方法的方式自己解决。

✅面向对象的五大基本原则?

博客 : 设计模式

五大基本原则: 单一职责原则(Single-Responsibility Principle) 、开放封闭原则(Open-Closedprinciple) 、Liskov替换原则 (Liskov-Substituion Principle) 、依赖倒置原则(Dependency-InversionPrinciple)和接门隔离原则(Interface-Segregation Principle)。

单一职责原则 : 一个类最好只做一件事

开放封闭原则 : 对扩展开放、对修改封闭

里氏替换原则 : 子类必须能够替换其基类

依赖倒置原则 : 程序要依赖于抽象接口,而不是具体的实现

接口隔离原则 : 使用多个小的专门的接口,而不要使用一个大的总接口

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

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

相关文章

buuctf-Misc 题目解答分解85-87

85.[UTCTF2020]file header 下载完就是一个图片 ,但是显示图片错误,提示文件头 没有 用010editor 打开 找一个png 文件,看一下它的头部 只需要修改前四个字节为 89 50 4E 47 即可 就能拿到flag utflag{3lit3_h4ck3r} 86.[WUSTCTF2020]gir…

蓝桥杯专题-真题版含答案-【三角螺旋阵】【干支记年法】【异或加密法】【金字塔】

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC 👉关于作者 专注于Android/Unity和各种游戏开发技巧,以及各种资源分…

v851s ssh搭建与使用

ssh 概述: 1. 用来远程登录的一种安全通道协议(常用于linux 、UNIX中); 2. 分为服务端和客户端: 1)服务端即openSSH ,一般属于目标开发板(linux中配置文件路径/etc/ssh/sshd_config); 2)客户端即登录端,常用工具:sercureCRT 、MobaXterm 、Putty等; 1. ssh 服务…

Webrtc 学习交流

花了几周的时间研究了一下webrtc ,并开发了一个小项目,用来点对点私密聊天 交流传输文件等…后续会继续扩展其功能。 体验地址,大狗子的ID,我在线时可以连接测试到我 f3e0d6d0-cfd7-44a4-b333-e82c821cd927 项目特点 除了交换信令与stun 没…

Hadoop分布式配置小白篇(附加各阶段问题解决方式)

看的黑马的课,记录一下配置步骤 目录 1.VMware安装: 方法1: 方法2: 2.创建虚拟机 1.ISO镜像文件获取(CentOS): 2.创建(简略步骤) 3.克隆虚拟机(克隆伪…

Flutter在Android Studio上创建项目与构建模式

一、安装插件 1、前提条件,安装配置好Android Studio环境 2、安装Flutter和Dart插件 Linux或者Windows平台: 1)、打开File > Settings。 2)、在左侧列表中,选择"Plugins"右侧上方面板选中 "Market…

向华为学习:基于BLM模型的战略规划研讨会实操的详细说明,含研讨表单(二)

上一篇文章,华研荟结合自己的经验和实践,详细介绍了基于BLM模型的战略规划研讨会的设计和组织流程,提高效率的做法。有朋友和我私信沟通说,其实这个流程不单单适合于BLM模型的战略规划研讨会,实际上,使用其…

【C++11特性篇】C++11中新增的initializer_list——初始化的小利器(2)

前言 大家好吖,欢迎来到 YY 滴C11系列 ,热烈欢迎! 本章主要内容面向接触过C的老铁 主要内容含: 欢迎订阅 YY滴C专栏!更多干货持续更新!以下是传送门! 目录 一.探究std::initializer_list是什么…

【MyBatis-Plus】MyBatis进阶使用

目录 一、MyBatis-Plus简介 1.1 介绍 1.2 优点 1.3 结构 二、MyBatis-Plus基本使用 2.1 配置 2.2 代码生成 2.3 CRUD接口测试 三、MyBatis-Plus策略详解 3.1 主键生成策略 3.2 雪花ID生成器 3.3 字段自动填充策略 3.4 逻辑删除 四、MyBatis-Plus插件使用 4.1 乐…

【笔试强化】Day 4

文章目录 一、单选1.2.3.4.5.6.7. 二、不定项选择1.2.3. 三、编程1. 计算糖果题解:代码: 2. 进制转换题解:代码: 一、单选 1. 正确答案:D队列先进先出 A:栈有关 B:错 C:错 2. 正确…

Linux centos7安装redis 6.2.14 gz并且使用systemctl为开机自启动 / 彻底删除 redis

1.下载 && 减压 wget http://download.redis.io/releases/redis-6.2.14.tar.gz tar -zvxf redis-6.2.14.tar.gz 2.编译(分开运行) cd redis-6.2.14 make cd src make install 安装目录展示 3.redis.conf 配置更改 daemonize yes supervised s…

轻量封装WebGPU渲染系统示例<48>- 多种光源的多种组合(源码)

实现方式: 1. 全局的灯光和阴影。 2. 球体和矩形平面使用了相同的材质对象。 3. 通过材质自动关联和组装对应的渲染材质功能节点。 当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/material/src/voxgpu/sample/MultiLightsShading2.ts 当前…

python 连接SQL server 请用pymssql连接,千万别用pyodbc

pymssql官方介绍文档 python 使用 pymssql连接 SQL server 代码示例: 安装pymssql包: pip install pymssql代码: import pymssqldef conn_sqlserver_demo():# 连接字符串示例(根据您的配置进行修改)conn Nonetry:co…

【C++】 C++11 新特性探索:decltype 和 auto

▒ 目录 ▒ 🛫 问题描述环境 1️⃣ decltype推导变量类型推导函数返回类型 2️⃣ auto自动推导变量类型迭代器和范围循环 3️⃣ decltype 和 auto 同时使用🛬 结论📖 参考资料 🛫 问题 描述 C11 引入了一些强大的新特性&#xff…

探索 HBase GUI 工具,助您轻松驾驭大数据世界!

你是否曾为 HBase 数据管理而苦恼?别担心,这一款超级好用的 HBase GUI (HBase Assistant)工具,让您在大数据世界中游刃有余。不再需要繁琐的命令行操作,也不再为复杂的配置感到头疼。 主要功能 直观和设计…

AttributeError: module ‘edge_tts‘ has no attribute ‘Communicate‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

插入排序:直接插入排序 希尔排序

插入排序: 假设红竖线前的元素全部排好序,红线后面的数即为要插入的数据,红线依次往后移,假设end为排好序的最后一个数字,end1即为要插入的数字,一次插入时,end与要插入的数字依次比较&#xf…

自定义时间选择器

自定义时间选择器 文章目录 自定义时间选择器第一章 效果演示第01节 效果图第02节 主要文件 第二章 案例代码第01节 核心文件 WheelPicker第02节 实体类 WheelBean第03节 接口类 IWheelPicker第04节 原子时间类 DateTimePickerView第05节 原子时间类 PickerYear第06节 原子时间…

比特币价格创新高:加密货币的崛起与未来

一、引言 近年来,比特币的价格一路上涨,引起了全球投资者和市场的广泛关注。作为最早一批区块链技术应用案例之一,比特币的成功带动了整个加密货币市场的兴起。本文将探讨比特币价格创新高的原因、加密货币的崛起以及未来发展趋势。 二、比特…

CV炼丹心得总结

1,ResNet的思想 yF(x)x 这个经验可帮助模型更快的收敛 class Block(nn.Module): # Encoder Blockdef __init__(self,dim, # 每个token的维度drop_rate0.1,switch_flagFalse,num_heads8):super(Block, self).__init__()self.switch_flag switch_flagself.…