重叠构造函数 、JavaBean模式、建造者模式、Spring的隐性大手
构造函数
- 重叠构造函数
- JavaBean模式
- 建造者模式构造
- Spring看起来为什么简单
- 番外篇
- 为什么在JavaBean中 无参构造函数是必须的呢
- 小结
构造函数对我来讲是很平常的一个东西,今天来谈谈新的收获。
重叠构造函数
通常我们定义好实体类后,不会特意的去调整构造函数。
public class Person {private int age;private String name;private int sex;private int weight;public Person(int age,String name,int sex,int weight){this.age = age;this.name = name;this.sex = sex;this.weight = weight;}
}
如果想要其中的某个参数得到固定的默认值来减少入参的个数,我们就可以采用重叠构造的形式。
public class Person {private int age;private String name;private int sex;private int weight;public Person(int age){// 调用到的依旧是下方的Person构造函数 而 后三个入参以默认值的形式进行赋值// Person(age,"jack",1,60)// 不过这种写法需要写在构造函数的首行this(age,"jack",1,60);}public Person(int age,String name){this(age,name,1,60);}public Person(int age,String name,int sex){this(age,name,sex,60);}public Person(int age,String name,int sex,int weight){this.age = age;this.name = name;this.sex = sex;this.weight = weight;}
}
上面所述的代码中,我们分别重载了三个方法,针对不同的默认参数进行区分,目前看起来虽然达到了目的,但随着入参的增多,显示是不可取的。
当然 如果可以的话,我们重载的几个方法可以在定义方法名的时候就采用不同的名称,方便使用者通过名称就可以进行区分而不是每次都进入方法内部进行识别。
JavaBean模式
面对多个可选入参的构造时,可采用JavaBean的形式去创建对象实例。
import java.io.Serializable;// 1. 实现 Serializable 接口 序列化方便数据持久化和网络传输
public class User implements Serializable {// 2. 私有属性private Long id;private String name;private String email;// 3. 无参构造器(必须)public User() {}// 4. Getter 和 Setter 方法(必须)public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}
}
上面的代码中,可以看出,不同的变量拥有独立的赋值逻辑,很好的解决了重叠构造带来的重复性设定的问题。
接着就要说他的坏处,有一句话是这么说的:“过于灵活的东西,同样代表他具有不可控性。”
书中是这么说的。
- 在构造函数被分到了多个调用中,构造的过程中JavaBean可能处于不一致的状态。
- JavaBean模式使得把类做成不可变的可能性不复存在
不一致可以从以下几个方面简单了解:
- 分步初始化导致中间状态不一致
创建一个Person对象需要调用setName()和setAge()。在仅设置setName()后,对象已存在但age可能为默认值(如0)。若此时其他代码读取该对象,可能得到无效数据。 - 违反约束
一个类中要求width和height必须同时为正数。通过JavaBeans分别设置时,可能在中间步骤出现width=10, height=-5的无效状态。 - 多线程读取问题
多线程环境下,线程A正在设置setName()和setAge(),线程B可能在中间状态读取到半初始化的Person对象。
面对JavaBean的灵活性,需要增加的限制应当就是部分可控性。
建造者模式构造
public class TestBuild {private final int age;private final String name;private final int sex;private final int weight;// 定义Build静态类public static class Builder{// 首先定义两个需要被限制的属性变量private final int sex;private final int age;// 随意可变属性变量private String name;private int weight;// 定义Build构造函数public Builder(int sex,int age){this.sex = sex;this.age = age;}// 利用类似setter的形式对可变参数赋值public Builder name(String val){this.name = val;return this;}public Builder weight(int val){this.weight = val;return this;}// 最终通过无参构造函数生成实例对象public TestBuild build(){return new TestBuild(this);}}// 将赋值好的build对象入参实例类的构造方法中进行赋值private TestBuild(Builder builder){// 构造时集中校验if (builder.age < 0){throw new IllegalArgumentException();}if (builder.sex != 0){throw new IllegalArgumentException();}age = builder.age;name = builder.name;sex = builder.sex;weight = builer.weight;}
}// 实例调用demo
TestBuild tb = new TestBuild.Builder(25,1).name("jack").weight(60).build();
建造者模式通过在类中设定一个新的静态类build,build类中围绕必传不可变参数生成构造函数,其余参数依旧按照setter的形式定义,build的整个过程不存在分步赋值的逻辑,最终将build作为入参统一的生成要返回的实例对象。
Spring看起来为什么简单
想到平时用的最多的Spring中,通常只是无参构造+getter/setter,那Spring帮我们做了什么事情来保证实例数值的一致性呢。
- Spring 支持ORM框架对实体对象进行数据库数据的写入绑定,而绑定的过程会通过反射一次性将所有字段都进行赋值后才会返回创建实例对象,构造过程由框架控制,无需手动处理,这也是让人我忽略掉的过程。
- Spring通过依赖注入机制管理Bean的依赖关系,确保Bean的创建和初始化过程由Spring容器统一控制,避免了手动管理Bean时可能出现的状态不一致问题。
- Spring支持多种Bean作用域(如Singleton、Prototype、Request、Session等),确保在不同场景下Bean的生命周期和状态管理的一致性。
- Spring提供了声明式事务管理,通过@Transactional注解或XML配置,确保数据库操作的一致性和原子性,避免了因事务未提交或回滚导致的数据不一致问题。
- Spring通过三级缓存机制解决Bean之间的循环依赖问题,确保Bean在初始化过程中不会因为循环引用(A、B类互相引用)而导致状态不一致。
- 一级缓存 存储已经实例化 赋值 初始化好的实例对象
- 二级缓存 存储已经实例化 但还未赋值的实例对象
- 三级缓存 实例还未创建 由spring生成代理对象先提供其他类获取
大致先了解这么几条。
番外篇
为什么在JavaBean中 无参构造函数是必须的呢
答:Spring是通过反射机制来对实例对象进行赋值的 而反射中获取对象实例的newInstance()方法就是对无参构造函数的调用
// JavaBean定义
public class User {private String name;public User() {} public void setName(String name) { this.name = name; }
}// 模拟Spring容器创建对象
public class SpringSimulator {public static void main(String[] args) throws Exception {// 步骤1:通过类全限定名获取Class对象Class<?> clazz = Class.forName("com.example.User");// 步骤2:调用newInstance()方法(依赖无参构造器)Object user = clazz.newInstance(); // 此时user对象已创建// 步骤3:通过反射调用setter方法注入属性Method setNameMethod = clazz.getMethod("setName", String.class);setNameMethod.invoke(user, "Alice");System.out.println(user); // 输出:User{name=Alice}}
}
但是回想平时的代码,一般情况下很少显式的书写无参构造函数,也不会报错,查了一番后可能是因为这只是javaBean的一种强制规范(可能会存在框架找不到显式无参构造而抛出异常的问题),而Spring中没有强制要求。
小结
小归小,妙归妙。
知道的不一定用得上,但是不知道的一定用不上。
还记得一开始接触框架的时候就明白它只是一种方便程序员的工具,但是渐渐地也让人们都蒙在了鼓里。
相关文章:
重叠构造函数 、JavaBean模式、建造者模式、Spring的隐性大手
构造函数 重叠构造函数JavaBean模式建造者模式构造Spring看起来为什么简单番外篇为什么在JavaBean中 无参构造函数是必须的呢 小结 构造函数对我来讲是很平常的一个东西,今天来谈谈新的收获。 重叠构造函数 通常我们定义好实体类后,不会特意的去调整构造…...
题单:精挑细选
题目描述 小王是公司的仓库管理员,一天,他接到了这样一个任务:从仓库中找出一根钢管。这听起来不算什么,但是这根钢管的要求可真是让他犯难了,要求如下: 1.1. 这根钢管一定要是仓库中最长的; …...
GGUF 和 llama.cpp 是什么关系
这是个非常关键的问题,咱们来细说下:GGUF 和 llama.cpp 是什么关系,它们各自干什么,如何配合工作。 🔧 一、llama.cpp 是什么? llama.cpp 是 Meta 的开源大语言模型 LLaMA(Language Model from…...
手机怎么换网络IP有什么用?操作指南与场景应用
在数字化时代,手机已经成为我们日常生活中不可或缺的一部分,无论是工作、学习还是娱乐,手机都扮演着至关重要的角色。而在手机的使用过程中,网络IP地址作为设备在互联网上的唯一标识符,其重要性和作用不容忽视。本文将…...
强化学习中的深度卷积神经网络设计与应用实例
I. 引言 强化学习(Reinforcement Learning,RL)是机器学习的一个重要分支,通过与环境的交互来学习最优策略。深度学习,特别是深度卷积神经网络(Deep Convolutional Neural Networks,DCNNs&#…...
软考程序员-操作系统基本知识核心考点和知识重点总结
以下是软考程序员考试中操作系统基本知识章节的核心考点和知识重点总结,结合历年真题和考试大纲整理而成: 一、操作系统基本概念与功能 定义与作用 操作系统是管理计算机软硬件资源的核心系统软件,负责协调程序执行、优化资源利用,…...
思源配置阿里云 OSS 踩坑记
按照正常的配置IAM,赋予OSS权限,思源笔记还是无法使用,缺少ListBuckets权限。 正常配置权限,又无法覆盖,因此需要手动配置权限。 {"Version": "1","Statement": [{"Effect":…...
科技赋能安全:慧通测控的安全带全静态性能测试
汽车的广泛普及给人们的出行带来了极大便利,但交通事故频发也成为严重的社会问题。据世界卫生组织统计,全球每年约有 135 万人死于道路交通事故,而安全带在减少事故伤亡方面起着不可替代的作用。正确使用安全带可使前排驾乘人员的死亡风险降低…...
记录修复一个推拉门滑轮
推拉门有个滑轮的固定螺丝不知什么时候掉了,也找不到,这就导致推拉门卡在轨道上。 这种滑轮在夕夕上很便宜,比哈罗单车还划算,但是现在缺的只是螺丝,如果买就会多出来一个轮… 这种螺丝比较长,大概是m4的…...
压缩壳学习
壳是什么 壳就是软件的一个保护套,防止软件被进行反编译或被轻易地修改。 其作用就是为了保护软件。 常见的大类壳有压缩壳、加密壳、VM 壳的分类。 压缩壳顾名思义就是用来减小软件的文件大小的;加密壳,通过加密软件来保护软件ÿ…...
深入理解 Linux ALSA 音频架构:从入门到驱动开发
文章目录 一、什么是 ALSA?二、ALSA 系统架构全景图核心组件详解:三、用户空间开发实战1. PCM 音频流操作流程2. 高级配置(asound.conf)四、内核驱动开发指南1. 驱动初始化模板2. DMA 缓冲区管理五、高级主题1. 插件系统原理2. 调试技巧3. 实时音频优化六、现代 ALSA 发展七…...
#13【CVPR2024】“不确定性不是敌人”:深入剖析多模态融合中的不确定性
📜 Embracing Unimodal Aleatoric Uncertainty for Robust Multimodal Fusion 本文没有源码,适合基础好的读者 🍞 1:研究背景与问题定义 🍫 1.1 多模态融合的黄金承诺与现实落差 在人工智能的迅猛发展浪潮中,多模态学习(Multimodal Learning)扮演着越来越重要的角…...
使用 QR-Code-Styling 在 Vue 3 中生成二维码
使用 QR-Code-Styling 在 Vue 3 中生成二维码 1. 前言 二维码广泛应用于网站跳转、支付、身份认证等场景。普通的二维码较为单调,而 qr-code-styling 允许我们自定义二维码的颜色、Logo、样式,使其更具个性化。本文将介绍如何在 Vue 3 Element Plus 中…...
CCF-CSP认证 202206-2寻宝!大冒险!
题目描述 思路 有一张绿化图和藏宝图,其中绿化图很大(二维数组在限定的空间内无法存储),而藏宝图是绿化图中的一部分,对于绿化图和藏宝图,左下角的坐标为(0, 0),右上角的坐标是(L, L)、(S, S)&…...
Redis项目:秒杀业务(优化)
当用户发起请求,此时会请求nginx,nginx会访问到tomcat,而tomcat中的程序,会进行串行操作,分成如下几个步骤 1、查询优惠卷 2、判断秒杀库存是否足够 3、查询订单 4、校验是否是一人一单 5、扣减库存 6、创建订单…...
《Gradio Python 客户端入门》
《Gradio Python 客户端入门》 Gradio Python 客户端使将任何 Gradio 应用程序用作 API 变得非常容易。例如,考虑这个 Hugging Face Space,它转录从麦克风录制的音频文件。 使用该库,我们可以轻松地将 Gradio 用作 API 以编程方式转录音频文…...
仿函数 VS 函数指针实现回调
前提: 本博客对比 函数指针实现回调 和 仿函数 ,突出仿函数的优势。 目的: 一个类要能够灵活的调用两个函数,essfc 和 greaterfc,分别用于比较两个整数的大小: ①:lessfc:判断 x …...
MQTT的安装和使用
MQTT的安装和使用 在物联网开发中,mqtt几乎已经成为了广大程序猿必须掌握的技术,这里小编和大家一起学习并记录一下~~ 一、安装 方式1、docker安装 官网地址 https://www.emqx.com/zh/downloads-and-install/broker获取 Docker 镜像 docker pull e…...
网络工程师考试详细介绍,讲解,备考方案
一、考试科目与形式 1. 科目1:基础知识(计算机与网络知识) - 考试形式:机考,75道选择题(含5道英文题),满分75分 - 核心内容: - 计算机系统:硬件组成&…...
ROS melodic 安装 python3 cv_bridge
有时候,我们需要处理这些兼容性问题。此处列举我的过程,以供参考 mkdir -p my_ws_py39/src cd my_ws_py39 catkin_make_isolated-DPYTHON_EXECUTABLE/usr/bin/python3 \-DPYTHON_INCLUDE_DIR/usr/include/python3.8 \-DPYTHON_LIBRARY/usr/lib/x86_64-l…...
SHELL练习01
判断一个数是奇数还是偶数 要求: 编写一个 Shell 脚本,用户输入一个整数,判断该数是奇数还是偶数,并输出结果。 [rootnode test01]# touch Determine parity.sh [rootnode test01]# vim Determine parity.sh 还有 2 个文件等待…...
PRODIGY: “不折腾人”的蛋白-蛋白/蛋白-小分子结合能计算工具
PRODIGY(全称为 PROtein binDIng enerGY prediction)是一种蛋白质结合能预测工具,可利用蛋白质-蛋白质复合物的三维结构来预测其结合亲和力。PRODIGY 利用一种高效的基于接触的方法,在估计结合自由能和解离常数的同时,…...
C++之 【模板初阶(函数模板与类模板)】
目录 1.泛型编程 2.模板 3函数模板 3.1函数模板的概念 3.2函数模板的格式 3.3函数模板的原理 3.4函数模板的实例化 3.4.1隐式实例化:让编译器根据实参推演模板参数的实际类型 3.4.2显示实例化:在函数名后的<>中指定模板参数的实际类型 3.…...
博弈论中的均衡精炼:完美贝叶斯均衡、序贯均衡与颤抖手均衡详解
博弈论中的均衡精炼:完美贝叶斯均衡、序贯均衡与颤抖手均衡详解 1. 引言:为什么需要均衡精炼? 在博弈论中,纳什均衡是分析策略互动的核心工具,但其存在一个显著缺陷:无法排除不合理的均衡。例如࿰…...
在线教育网站项目第四步:deepseek骗我, WSL2不能创建两个独立的Ubuntu,但我们能实现实例互访及外部访问
一、说明 上一章折腾了半天,搞出不少问题,今天我们在deepseek的帮助下,完成多个独立ubuntu24.04实例的安装,并完成固定ip,实践证明,deepseek不靠谱,浪费我2个小时时间,我们将在下面实…...
在刀刃上发力:如何精准把握计划关键节点
关键路径分析是项目管理中的一种重要方法,它通过在甘特图中识别出项目中最长、最关键的路径,来确定项目的最短完成时间。 关键路径上的任务都是项目成功的关键因素,任何延误都可能导致整个项目的延期。关键路径分析对于项目管理者来说至关重要…...
组合总和||
1.给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用一次。 #include <bits/stdc.h> using namespace std; vector<vector<int>> result; vec…...
OpenCV图像拼接(2)基于羽化(feathering)技术的图像融合算法拼接类cv::detail::FeatherBlender
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::detail::FeatherBlender 是 OpenCV 中用于图像拼接的一个类,它属于 stitching 模块的一部分。这个类实现了基于羽化(…...
MediaPipe软件包如何构建和安装
MediaPipe 是一个由 Google 开发的多媒体机器学习框架,支持多种平台(如 Android、iOS、桌面等)。以下是构建和安装 MediaPipe 的步骤: 1. 环境准备 确保系统满足以下要求: 操作系统: Ubuntu (推荐 18.04 或 20.04)、…...
分享下web3j 常见用法
转账 fun sendEthTransaction(privateKey: String,toAddress: String,amount: BigDecimal) {//chainIdval chainId:Long 1//url 可以从https://chainlist.org/里面获取可用节点//eth转账,bnb同理,但需发送到bnb对应节点val url "https://xxx"…...
