2026-02-06

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)。你只需要记住几个核心动词:

  1. clean:相当于 rm -rf bin/。删掉旧的编译结果,保证环境干净。
  2. compile:相当于 g++ -c。把源码变成字节码。
  3. package:打包。把编译后的代码、配置文件塞进一个 .jar 文件里。
  4. install:把这个打好的包“发布”到你 Mac 本地的 .m2 仓库里。这样如果你以后写第 2 个项目,就可以直接通过 pom.xml 引用这个项目的代码了。

现在实践一下各个指令的效果:

mvn clean
Pasted image 20260206123620

这个就是编译,然后编译的参考文件是pom.xml, 结果是导出到target文件夹当中的:

mvn compile
Pasted image 20260206123740
mvn package
  1. 它会自动重新执行 compile(如果代码没变会跳过)。 2. 在 target 目录下生成了一个名为 JavaSE01_01-1.0-SNAPSHOT.jar 的文件。
Pasted image 20260206124015

然后这个目录相当于可执行文件,可以直接运行,

java -jar target/JavaSE01_01-1.0-SNAPSHOT.jar
Pasted image 20260206124458

编译打包和保存到本地:

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

项目架构如下,现在分析一下里面的文件:

Pasted image 20260206130932 `_remote.repositories:`
#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标签即可。

Pasted image 20260206130729

C、xml文件架构解析

pom

现在分析一下最基础的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("---------------------------");  
    }  
}

期间内存有些吃紧,找了半天才把内存修改过来:

Pasted image 20260206194505

B、理论学习

第一层级:跨项目访问

最远的距离,两个代码存在于完全不同的项目文件夹中(甚至可能在不同的电脑上)。

Pasted image 20260206194803

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 写的库)。 操作步骤

  1. 确定坐标:获取目标的 groupId, artifactId, version
  2. 配置 POM:在 <dependencies> 里加上坐标。
  3. 刷新 Maven:让 IDE 下载或关联这个包。
  4. 打包处理:如果最后要运行,必须用 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 install
2. 自己加 <dependency>
链接静态库 .a / .lib
第三方库 互联网 (GitHub等) 进口 1. 查坐标 (GAV)
2. 自己加 <dependency>
vcpkgapt-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,没有第一个项目当中所调用的内容。

Pasted image 20260206210251

第二个包解包结果如下,可以看到又三个函数所对应的包,第二个包是导入了两个第一个项目的包。

Pasted image 20260206210430

运行第二个代码效果如下:

java -jar target/JavaSE01_02_CallTest-1.0-SNAPSHOT-jar-with-dependencies.jar
Pasted image 20260206200920

五、Java语法上手

快速尝试了一下Java的打印函数和输入函数,不过要理解其原理,还是得系统性的看一下教程。

这里就不做展开了,测试代码的时候,不需要运行xml,这个是大项目的配置方法,简单测试一个代码的时候,直接使用Java IDE上面绿色的箭头运行就可以了。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 kipleyarch@gmail.com
Obsidian