【Java 基础篇】Java 模块化详解
Java 9引入了一项重要的功能:模块化(Module System)。模块化是一种将代码和资源封装到可重用和独立的单元中的方法,它有助于改善代码的可维护性、可重用性和安全性。本文将介绍Java模块化的基本概念、如何创建和使用模块以及一些最佳实践。
什么是Java模块化?
在Java 9之前,Java应用程序是以JAR文件的形式组织的,其中包含了一堆类和资源。这种方式存在一些问题:
- 可维护性差:JAR文件可以包含大量的类和资源,这使得应用程序的结构变得混乱,难以维护。
- 可重用性差:在多个应用程序之间共享代码和资源比较困难。
- 安全性问题:所有的类都在同一个类路径中,这可能导致意外的访问和依赖关系。
Java模块化解决了这些问题。模块是一种新的编程单元,它可以包含类、资源和其他模块的依赖关系。模块化的代码更容易维护,更容易重用,同时也提供了更好的安全性。
模块化的基本概念
在开始使用Java模块化之前,让我们先了解一些基本概念:
1. 模块(Module)
一个模块是一个可重用的单元,它包含了一组相关的类和资源。每个模块都有一个名字,并可以声明自己的依赖关系。
2. 模块声明(Module Declaration)
一个模块声明是一个包含在module-info.java
文件中的文件,它定义了一个模块的名称、依赖关系和其他特性。
3. 模块路径(Module Path)
模块路径是一组目录和JAR文件,其中包含了模块的JMOD文件和module-info.class
文件。模块路径用于告诉JVM哪些模块可用。
4. 模块化 JAR 文件(Modular JAR File)
模块化JAR文件是一种特殊类型的JAR文件,它包含了一个模块的类和资源,以及module-info.class
文件。
5. 自动模块(Automatic Module)
如果一个JAR文件没有module-info.class
文件,它被称为自动模块。自动模块的名称基于JAR文件的文件名,并且具有一些默认的依赖关系。
6. 依赖性(Dependency)
一个模块可以声明对其他模块的依赖关系,以便在编译时和运行时使用其他模块的类和资源。
创建一个简单的模块
让我们从创建一个简单的Java模块开始,以便更好地理解模块化的概念。假设我们有一个应用程序,它有两个模块:一个模块用于处理数据库连接,另一个模块用于处理用户界面。
第一步:创建数据库模块
首先,我们创建一个数据库模块,它包含了一个简单的类DatabaseConnection
:
// DatabaseConnection.java
package com.example.database;public class DatabaseConnection {public void connect() {System.out.println("Connected to the database.");}
}
然后,我们为该模块创建一个module-info.java
文件,声明该模块的名称:
// module-info.java
module databaseModule {
}
这个模块不依赖于其他模块,所以module-info.java
文件中没有声明任何依赖关系。
第二步:创建用户界面模块
接下来,我们创建一个用户界面模块,它包含了一个简单的类UserInterface
:
// UserInterface.java
package com.example.ui;public class UserInterface {public void display() {System.out.println("User interface displayed.");}
}
为该模块创建一个module-info.java
文件,声明该模块的名称和对数据库模块的依赖:
// module-info.java
module uiModule {requires databaseModule;
}
这个模块声明了对databaseModule
的依赖,这意味着它可以使用databaseModule
中的类和资源。
第三步:编译和运行模块
现在,我们可以使用Java 9编译器来编译这两个模块:
javac -d out/database databaseModule/*.java
javac -d out/ui --module-path out databaseModule/*.java uiModule/*.java
然后,我们可以运行UserInterface
类来启动我们的应用程序:
java --module-path out -m uiModule/com.example.ui.UserInterface
这将会输出:
Connected to the database.
User interface displayed.
模块化的更多操作
当您在Java应用程序中使用模块化时,可以执行许多不同的操作,以更好地组织、管理和优化您的代码。以下是一些模块化的更多操作:
-
导出和打包模块:您可以使用
exports
关键字在module-info.java
中声明哪些包可以被其他模块访问。这允许您控制哪些部分的代码对外可见。例如:module myModule {exports com.example.mypackage; }
您还可以使用
opens
关键字导出包,以便其他模块可以反射地访问包中的非公开类型。 -
开放模块:如果您希望模块对所有其他模块开放,可以使用
open
关键字。这对于编写插件或扩展模块很有用。module myModule {open com.example.mypackage; }
-
命令行工具:Java 9引入了一些命令行工具,如
jdeps
,用于分析模块之间的依赖关系,以及jlink
,用于创建自定义运行时映像。 -
运行时图像:您可以使用
jlink
命令将您的模块化应用程序与JRE一起打包成自定义运行时图像。这有助于减小应用程序的大小,因为只包括了应用程序所需的模块。 -
模块路径:模块路径是一个包含模块的目录或JAR文件的集合,它用于在运行时加载模块。您可以使用
--module-path
选项来指定模块路径。 -
自动模块:如果您的应用程序包含非模块化的JAR文件,Java会自动将它们转换为自动模块,以便它们可以与模块一起使用。
-
模块化JAR文件:您可以使用
jar
工具创建模块化的JAR文件,其中包含了模块描述文件(module-info.class
)。 -
模块化库:许多常用的Java库已经进行了模块化,以便更好地与模块化应用程序集成。您可以在模块路径上指定这些库,而无需手动管理它们的依赖关系。
-
模块化测试:使用模块路径和
--module
选项,您可以在单元测试中模拟模块化环境。 -
版本管理:在
module-info.java
中可以使用requires static
关键字来声明可选依赖关系,这些依赖关系只在模块可用时才会生效。
这些是模块化Java应用程序中的一些更多操作。模块化使得Java应用程序更易于维护和扩展,同时提供了更好的封装和可重用性。根据您的项目需求,您可以选择适当的操作来更好地利用模块化的优势。
模块化的最佳实践
以下是一些模块化的最佳实践:
-
模块命名规范:给模块取一个有意义的名字,通常使用逆域名表示法(例如:
com.example.myapp
)。 -
明确的依赖关系:在
module-info.java
文件中明确声明模块的依赖关系,以确保应用程序的模块之间的依赖关系清晰可见。 -
最小依赖原则:尽量减少模块之间的依赖关系,只依赖于真正需要的模块。
-
版本化的依赖关系:如果可能的话,使用版本化的依赖关系来确保模块依赖的是正确的版本。
-
单一责任原则:将每个模块限制为一个特定的功能或领域,以提高可维护性和可重用性。
-
测试和验证:确保模块之间的依赖关系和交互在编译时和运行时都能正常工作。
-
模块路径管理:管理模块路径以确保应用程序能够正确加载和运行。
注意事项
在编写和使用模块化的Java应用程序时,有一些重要的注意事项,以确保您的应用程序正确运行和维护。以下是一些模块化的注意事项:
-
模块依赖关系:仔细考虑您的模块之间的依赖关系。确保模块之间的依赖关系是明确的,避免循环依赖。使用
requires
语句声明依赖关系,并根据需要使用requires transitive
或requires static
。 -
版本管理:了解模块之间的版本管理。Java 9引入了模块化版本的概念,允许模块依赖于特定版本的其他模块。考虑使用
requires static
来声明可选的、仅在特定版本下才有效的依赖关系。 -
模块命名:为您的模块选择合适的名称。模块名称应该唯一且易于理解。遵循Java的包命名约定,使用反向域名(例如
com.example.mymodule
)。 -
模块路径:在运行应用程序时,使用
--module-path
选项指定模块路径。确保正确设置模块路径,以便Java可以找到并加载您的模块。 -
非模块化库:如果您使用了非模块化的JAR文件,将其包装为自动模块或创建模块化的版本。非模块化库的依赖关系可能会引入复杂性。
-
模块化库:考虑使用已经模块化的库,以减少与模块路径和版本管理相关的问题。
-
运行时图像:如果您使用
jlink
创建自定义运行时图像,请确保包括了所有必要的模块,并排除不必要的模块,以减小应用程序的大小。 -
测试:编写单元测试以确保模块化应用程序的正确性。使用模块路径和
--module
选项来模拟模块化环境进行测试。 -
模块描述文件:模块描述文件(
module-info.java
)是模块化应用程序的关键组成部分。确保正确声明依赖关系、导出和打包模块,以及使用其他关键字来管理可见性。 -
模块间通信:模块之间的通信应该在依赖模块的基础上进行。不要尝试绕过模块系统的可见性控制。
-
跨模块访问:如果需要在模块之间共享数据或访问非公开成员,请使用
opens
和opens...to
语句,以允许受信任的模块进行反射操作。 -
性能和内存开销:模块化应用程序的启动时间和内存开销可能会有所增加。在部署和测试应用程序时,要考虑性能方面的因素。
-
迁移:如果您正在迁移现有的应用程序到模块化架构,确保逐步迁移,以减少中断和问题。
-
文档和培训:为开发团队提供关于模块化的文档和培训,以确保所有开发人员都理解和遵守模块化的最佳实践。
-
工具支持:使用Java 9及更高版本,以充分利用模块化系统和相关的工具,如
jdeps
、jlink
和jmod
。
这些注意事项有助于确保您的模块化Java应用程序能够正确运行
结论
Java模块化是一个强大的工具,可以帮助您更好地组织和管理代码,提高可维护性和可重用性。本文介绍了模块化的基本概念,以及如何创建和使用模块。遵循最佳实践,可以使您的Java应用程序更加健壮和可维护。希望本文对您理解Java模块化有所帮助。
作者信息 作者 : 繁依Fanyi CSDN: https://techfanyi.blog.csdn.net 掘金:https://juejin.cn/user/4154386571867191 |
相关文章:

【Java 基础篇】Java 模块化详解
Java 9引入了一项重要的功能:模块化(Module System)。模块化是一种将代码和资源封装到可重用和独立的单元中的方法,它有助于改善代码的可维护性、可重用性和安全性。本文将介绍Java模块化的基本概念、如何创建和使用模块以及一些最…...
【2023面试题大全,都是常问面试题】
JAVA基础 面向对象和面向过程的区别 面向过程:基于步骤的编程方式,用函数把这些步骤一步一步地实现,然后在使用的时候一一调用则可 面向对象:基于对象的编程方式,通过定义类来描述对象的属性和行为,面向对…...

Bun 1.0 正式发布,爆火的前端运行时,速度遥遥领先!
文章目录 一、包子1.0二、Bun 是一个一体化工具包为什么包子存在 二、Bun 是一个 JavaScript 运行时Node.js 兼容性速度TypeScript 和 JSX 支持ESM 和 CommonJS 兼容性网络 API热重载插件 一、包子1.0 Bun 1.0终于来了。 Bun 是一个快速、一体化的工具包,用于运行…...
getchar函数设置为非阻塞
一. 前言 我们在学习C语言的时候,getchar都是阻塞的,等待用户输入字符并且输入回车后才返回。但是有时候我们希望把getchar设置为非阻塞,或者说,当我们遇到getchar函数变成非阻塞的了,我们应该怎么解决这个问题&#x…...
【超算作业调度系统--LSF】
集群服务器--LSF作业调度系统使用 0 Introdutction1 命令1.1 bsub--作业提交命令1.1.1 $ bqueues --查看现有队列信息;1.1.2 $lsload --查看各节点运行情况1.1.3 $bhosts --查看各节点空闲情况1.1.4 $busers --查看用户信息1.2 bsub --提交作业1.2.1 bsub OMP_NUM_T…...
L1-011 A-B分数 20
本题要求你计算A−B。不过麻烦的是,A和B都是字符串 —— 即从字符串A中把字符串B所包含的字符全删掉,剩下的字符组成的就是字符串A−B。 输入格式: 输入在2行中先后给出字符串A和B。两字符串的长度都不超过104,并且保证每个字符…...
PHPword解析内容支撑
因有些功能不支持,所以新增了某些功能,以防后期变动不好变更,手动做个记录 将公式替换成指定的符号,读取到 html 后读取 xml 解析公式,根据标记符号进行替换 文件名PhpOffice\PhpWord\Shared\XMLReader.php public fun…...

回归预测 | MATLAB实现RUN-XGBoost龙格库塔优化极限梯度提升树多输入回归预测
回归预测 | MATLAB实现RUN-XGBoost多输入回归预测 目录 回归预测 | MATLAB实现RUN-XGBoost多输入回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现RUN-XGBoost多输入回归预测(完整源码和数据) 1.龙格库塔优化XGBoost,…...

LLM-TAP随笔——语言模型训练数据【深度学习】【PyTorch】【LLM】
文章目录 3、语言模型训练数据3.1、词元切分3.2、词元分析算法 3、语言模型训练数据 数据质量对模型影响非常大。 典型数据处理:质量过滤、冗余去除、隐私消除、词元切分等。 训练数据的构建时间、噪音或有害信息情况、数据重复率等因素都对模型性能有较大影响。训…...
Linux- open() lseek()
文件描述符 文件描述符(File Descriptor,简称 FD)是 UNIX 和 UNIX-like 系统中用于代表和识别打开的文件或其他I/O资源的一种抽象标识。它是一个非负整数,内部由操作系统进行管理和分配。文件描述符可以代表文件、套接字、管道等…...
Halcon Tuple相关算子(一)
(1) tuple_length( : : Tuple : Length) 功能:返回输入元组中元素的个数。 控制输入参数: Tuple:输入元组; 控制输出参数:length:输入元组中元素的个数。 (2) tuple_find( : : Tuple, ToFind : Indices…...

基于图像形态学处理的路面裂缝检测算法matlab仿真
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ...................................................... %1:从文件夹中读取多个…...

PY32F003F18之窗口看门狗
一、PY32F003F18窗口看门狗特点: 即使窗口看门狗被禁止,窗口看门狗的"递减计数器"也会继续递减计数。 二、窗口看门狗复位的条件: 1、将"控制寄存器WWDG_CR"中的WDGA1,激活"窗口看门狗计数器等于0x3F"时,则产…...

SpingBoot:整合Mybatis-plus+Druid+mysql
SpingBoot:整合Mybatis-plusDruid 一、特别说明二、创建springboot新工程三、配置3.1 配置pom.xml文件3.2 配置数据源和durid连接池3.2.1 修改application.yml3.2.2 新增mybatis-config.xml 3.3 编写拦截器配置类 四、自动生成代码五、测试六、编写mapper.xml&#…...

计算机视觉与深度学习-经典网络解析-VGG-[北邮鲁鹏]
目录标题 VGG参考VGG网络贡献使用尺寸更小的$3 \times 3$卷积串联来获得更大的感受野放弃使用$11 \times 11$和$5 \times 5$这样的大尺寸卷积核深度更深、非线性更强,网络的参数也更少;去掉了AlexNet中的局部响应归一化层(LRN)层。 网络结构主要改进输入…...

入门级制作电子期刊的网站推荐
随着数字化时代的到来,越来越多的人开始尝试制作自己的电子期刊。如果你也是其中的一员,那么这篇文章可以帮助你制作电子期刊。无论是初学者还是有一定经验的制作者,都能快速完成高质量的电子期刊制作 小编经常使用的工具是-----FLBOOK在线制…...

软件测试内容整理
1. 软件测试 1.1. 定义 软件测试(英语:Software Testing),描述一种用来促进鉴定软件的正确性、完整性、安全性和质量的过程。换句话说,软件测试是一种实际输出与预期输出之间的审核或者比较过程。 软件测试的经典定…...

UniAccess Agent卸载
异常场景: UniAccess Agent导致系统中的好多设置打不开 例如:ipv4的协议,注册表,host等等 需要进行删除,亲测有效,及多家答案平凑的 借鉴了这位大神及他里面引用的大神的内容 https://blog.csdn.net/weixin_44476410/article/details/121605455 问题描述 这个进…...

【C++】C++11——构造、赋值使用条件和生成条件
移动构造和移动赋值生成条件移动构造和移动赋值调用逻辑强制生成默认函数的关键字default禁止生成默认函数的关键字delete 移动构造和移动赋值生成条件 C11中新增的移动构造函数和移动赋值函数的生成条件为: 移动构造函数的生成条件:没有自己实现的移动…...

【LeetCode热题100】--56.合并区间
56.合并区间 排序: 如果按照区间的左端点排序,那么在排完序的列表中,可以合并的区间一定是连续的,如下图所示,标记为蓝色、黄色和绿色的区间分别可以合并为一个大区间,它们在排完序的列表中是连续的 算法&a…...

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...