02月06日
一、今日完成情况
- 跑一个配置依赖和插件的项目,我需要看看依赖和插件的使用方法。
- 包括理解git配置文件、xml配置文件(完成)、理解昨天的小项目。
二、今日感悟
- 核心业务数据:
- Java架构快速了解
- xml文件快速了解
- 引用其他库文件,其他包快速了解
- print和 cin快速了解
- 今日工作总结:
- 基础语法,基础通用架构,没啥好说的
- 明日工作计划:
- 明天继续快速上手包括循环等语法
- 今日学习成长:
- 无
三、备注
- 无
四、Java基础知识理解
1、编译打包代码:
A、背景知识:Maven
对于我这种有C++基础的选手来说,Java的Maven可以对标makefile,可是看起来配置比C++要简单许多。
| 功能维度 | C++ 世界 | Java (Maven) 世界 | 极客理解 |
|---|---|---|---|
| 项目定义 | Makefile / CMakeLists.txt |
pom.xml |
声明式配置,定义“我是谁”和“我要怎么造”。 |
| 库管理 | 手动下载 .so / .a,配置 Include Path |
<dependencies> |
声明坐标,Maven 自动去中央仓库下载并关联。 |
| 编译指令 | make / cmake --build |
mvn compile |
统一的指令集,不管项目多大,命令都一样。 |
| 产物封装 | .exe / .dll |
.jar (Java Archive) |
把所有代码和资源压成一个压缩包。 |
pom.xml $\approx$ CMakeLists.txt |
Maven 最强的地方在于它的生命周期 (Lifecycle)。你只需要记住几个核心动词:
clean:相当于rm -rf bin/。删掉旧的编译结果,保证环境干净。compile:相当于g++ -c。把源码变成字节码。package:打包。把编译后的代码、配置文件塞进一个.jar文件里。install:把这个打好的包“发布”到你 Mac 本地的.m2仓库里。这样如果你以后写第 2 个项目,就可以直接通过pom.xml引用这个项目的代码了。
现在实践一下各个指令的效果:
mvn clean
这个就是编译,然后编译的参考文件是pom.xml, 结果是导出到target文件夹当中的:
mvn compile
mvn package
- 它会自动重新执行
compile(如果代码没变会跳过)。 2. 在target目录下生成了一个名为JavaSE01_01-1.0-SNAPSHOT.jar的文件。
然后这个目录相当于可执行文件,可以直接运行,
java -jar target/JavaSE01_01-1.0-SNAPSHOT.jar
编译打包和保存到本地:
mvn install
[INFO] Installing /Users/kipley/Documents/code/Java/JavaSE01_01/pom.xml to /Users/kipley/.m2/repository/org/example/JavaSE01_01/1.0-SNAPSHOT/JavaSE01_01-1.0-SNAPSHOT.pom
[INFO] Installing /Users/kipley/Documents/code/Java/JavaSE01_01/target/JavaSE01_01-1.0-SNAPSHOT.jar to /Users/kipley/.m2/repository/org/example/JavaSE01_01/1.0-SNAPSHOT/JavaSE01_01-1.0-SNAPSHOT.jar
如日志所示,会打包/Users/kipley/Documents/code/Java/JavaSE01_01/pom.xml 和 我的rar文件 /Users/kipley/Documents/code/Java/JavaSE01_01/target/JavaSE01_01-1.0-SNAPSHOT.jar 到我的系统文件夹当中,xml文件变成pom文件
JavaSE01_01-1.0-SNAPSHOT.pom 文件,其实就是项目中 pom.xml 的副本
最终保存位置如下:/Users/kipley/.m2/repository/org/example/JavaSE01_01/1.0-SNAPSHOT/JavaSE01_01-1.0-SNAPSHOT.jar
项目架构如下,现在分析一下里面的文件:
#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
#Fri Feb 06 12:54:56 CST 2026
JavaSE01_01-1.0-SNAPSHOT.jar>=
JavaSE01_01-1.0-SNAPSHOT.pom>=
Maven 本地仓库的 “物流标签”。它不包含你的代码逻辑,只是 Maven 为了保证依赖管理准确性而留下的运行痕迹。
- 内容:对于本地安装的项目,它会把
JavaSE01_01-1.0-SNAPSHOT.jar标记为本地来源。这样下次你引用它时,Maven 就知道:“哦,这是这台电脑自己产生的,不需要去网上找。”
JavaSE01_01-1.0-SNAPSHOT.pom:
这个文件内容和我配置的pom.xml文件内容一模一样,所以算是一个备份吧。
B、打包路径位置
Maven 的本地仓库默认路径是:/Users/kipley/.m2/repository,所以mvn install 之后的默认位置就是这个位置,后续的文件命名是有严格的规范的:
Maven 会严格按照你 pom.xml 中的坐标(GAV)来存放文件:
- 路径规则:
groupId(点号换成斜杠) +artifactId+version。
以你的项目为例:
groupId:org.example→ 转换为文件夹org/example/artifactId:JavaSE01_01→ 转换为文件夹JavaSE01_01/version:1.0-SNAPSHOT→ 转换为文件夹1.0-SNAPSHOT/
不需要看下面的dependency和build的标签,只需要查看顶部的GAV标签即可。
C、xml文件架构解析
现在分析一下最基础的xml配置文件的架构:
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>JavaSE01_01</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Archetype - JavaSE01_01</name>
<url>http://maven.apache.org</url>
这里的1.0-SNAPSHOT需要解释一下,为什么是这样命名的:
1.0-SNAPSHOT:代表开发中版本。每次install都会覆盖旧文件。1.0:代表正式版。Maven 规范中,正式版一旦install就不建议频繁更改。
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
编译器和编码格式,这个是固定的。
<dependencies>
<dependency> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency></dependencies>
Lombok 的本质是一个代码生成工具。它通过在类上添加特殊的“注解”(以 @ 开头),在编译阶段自动帮你写那些枯燥的重复代码。就是打包好的库,可以直接用,节约时间,常见的用法里面应该都有我未来需要的时候开个坑。
<build>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<mainClass>org.example.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
在 Java 中,一个项目可以有成千上万个 .class 文件,且其中多个类都可以拥有 public static void main 方法。
这就产生了一个问题:当你运行 java -jar app.jar 时,JVM 根本不知道该从哪个类的 main 方法开始执行。这段代码的作用就是 “指定唯一的官方入口”。
开始接触 Spring Boot 等高级框架时,不再需要手动配置 maven-jar-plugin。
- 原因:框架自带的
spring-boot-maven-plugin会自动扫描你的代码,找到那个带有@SpringBootApplication注解的类,并自动帮你填好这个入口。
D、关于target文件夹内容
| 文件/目录 | 学习侧重点 | 掌握要求 |
|---|---|---|
.jar 文件 |
运行指令、交付规范 | 精通 |
classes/ |
包路径映射、字节码原理 | 理解 |
generated-sources |
注解处理器原理 (Lombok) | 知道位置 |
| 其他文件夹 | 忽略,那是 Maven 的私事 | 视而不见 |
| 了解即可,不需要知道里面是干嘛的,这是编译器的事情。 |
2、项目实践
A、背景
我已经使用mvn install的方法,保存了我本地的刚才的代码可运行tar文件,我现在要在另一个项目当中测试使用它,现在进行尝试查看如何使用其他库,或者其他包。
package org.example; // 这里的包名要对应你 pom.xml 里的 groupId
public class Main {
public static void main(String[] args) {
System.out.println("--- Java 21 环境启动成功 ---");
// 获取操作系统名称 (类似 C++ 的 #ifdef _WIN32) String os = System.getProperty("os.name");
System.out.println("当前操作系统: " + os);
// 获取 CPU 核心数
int processors = Runtime.getRuntime().availableProcessors();
System.out.println("可用 CPU 核心数: " + processors);
System.out.println("---------------------------");
}
}
期间内存有些吃紧,找了半天才把内存修改过来:
B、理论学习
第一层级:跨项目访问
最远的距离,两个代码存在于完全不同的项目文件夹中(甚至可能在不同的电脑上)。
artifactId指定项目名字,version指定项目版本,groupId:指定项目位置。所以这里使用的是保存在本地的项目,系统默认回到本地仓库~/.m2/repository 寻找编译好的 JAR 包。
前提:这就是为什么必须先在第一个项目中运行 mvn install。这个命令负责把“源码”变成仓库里的“商品”。
第二层级:同项目,不同包
举例,现在有两个Java文件,路径是这样的:
src/main/java/org/example/Main.java(消费者)src/main/java/org/example/utils/Tools.java(被调用者)
就是说,都是在同一个项目当中,只不过是相对路径不同的情况下,只需要直接import就可以了,举例如下:
package org.example;
// 【关键动作】引入不同包的类
import org.example.utils.Tools;
public class Main {
public void run() {
Tools.doSomething(); // 直接调用
}
}
举一反三(通用):
场景:你要用任何 外部 的东西(不管是你写的另一个项目,还是 Google 写的库)。 操作步骤:
- 确定坐标:获取目标的
groupId,artifactId,version。 - 配置 POM:在
<dependencies>里加上坐标。 - 刷新 Maven:让 IDE 下载或关联这个包。
- 打包处理:如果最后要运行,必须用 Assembly 或 Shade 插件把依赖打进去。
所以,无论是本地还是从网络下载,都是这个流程,至于插件的配置,我需要重点说一下:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<archive>
<manifest>
<mainClass>org.example.CallTest</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
- Assembly 插件的作用:
- 普通的
maven-jar-plugin只打包你当前写的代码。 maven-assembly-plugin(配置了jar-with-dependencies) 的作用是做一个 “物理搬运”:它会跑去仓库,把JavaSE01_01.jar解压,把里面的.class文件拿出来,和当前项目的.class文件揉在一起,打成一个超级大包。
- 普通的
| 场景 | 物理位置 | 逻辑距离 | 你需要做什么? | 是否修改 POM? | C++ 类比 |
|---|---|---|---|---|---|
| 同包访问 | 同一个文件夹 | 邻居 | 直接调用类名 | ❌ 否 | 同一目录下的 .cpp |
| 跨包访问 | src 下的不同文件夹 |
同城 | 代码中写 import xxx; |
❌ 否 | #include 头文件 |
| 跨项目访问 | 不同的 Project 目录 | 异地 | 1. 对方 mvn install2. 自己加 <dependency> |
✅ 是 | 链接静态库 .a / .lib |
| 第三方库 | 互联网 (GitHub等) | 进口 | 1. 查坐标 (GAV) 2. 自己加 <dependency> |
✅ 是 | vcpkg 或 apt-get |
C、动手实践
此代码访问我编译好的jar文件的函数:
package org.example;
public class CallTest {
public static void main(String[] args) {
System.out.println("--- 正在尝试调用 JavaSE01_01 中的库 ---");
// 调用你在第一个项目里写好的静态方法
String message = MyUtils.getGreeting("Caprina");
System.out.println("返回结果: " + message);
}
}
对应已经修改了我的xml文件,实现可以访问我第一个项目封装好的函数的效果:
mvn compile
[INFO] Installing .../JavaSE01_02_CallTest-1.0-SNAPSHOT.jar
[INFO] Installing .../JavaSE01_02_CallTest-1.0-SNAPSHOT-jar-with-dependencies.jar
可以发现,编译出了两个jar文件,从文件的命名可以看出来,第二个是使用了项目一的依赖函数的,第一个没有使用依赖函数,那么问题来了,为什么需要导出第一个jar文件呢?
安装包解压
用解压命令(或 jar tf 指令)查看这两个包的内部:
jar tf target/JavaSE01_02_CallTest-1.0-SNAPSHOT.jar
jar tf target/JavaSE01_02_CallTest-1.0-SNAPSHOT-jar-with-dependencies.jar
第一个包解包结果如下,可以看到只有本次的项目代码对应的CallTest.class,没有第一个项目当中所调用的内容。
第二个包解包结果如下,可以看到又三个函数所对应的包,第二个包是导入了两个第一个项目的包。
运行第二个代码效果如下:
java -jar target/JavaSE01_02_CallTest-1.0-SNAPSHOT-jar-with-dependencies.jar
五、Java语法上手
快速尝试了一下Java的打印函数和输入函数,不过要理解其原理,还是得系统性的看一下教程。
这里就不做展开了,测试代码的时候,不需要运行xml,这个是大项目的配置方法,简单测试一个代码的时候,直接使用Java IDE上面绿色的箭头运行就可以了。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 kipleyarch@gmail.com