Content Table

Java Classpath 加载 jar 的顺序

以在 Test.java 中加载 app-1.jar 和 app-2.jar 中的类 com.xtuer.Aloha 为例演示 classpath 中 jar 被加载的顺序。

app-1.jar 和 app-2.jar

创建项目,里面只有 1 个类 com.xtuer.Aloha,分别打包成 2 个版本的 jar 包:

  • app-1.jar: 返回 Aloha-1
  • app-2.jar: 返回 Aloha-2
1
2
3
4
5
6
7
8
9
package com.xtuer;

public class Aloha {
@Override
public String toString() {
return "Aloha-1"; // app-1.jar 使用
// return "Aloha-2"; // app-2.jar 使用
}
}

项目的目录结构 (此 gradle 管理的 Java 项目结构仅作为参考):

1
2
3
4
5
6
7
8
app
├── build.gradle
└── src
└── main
└── java
└── com
└── xtuer
└── Aloha.java

测试项目

项目的目录结构:

1
2
3
4
5
6
jar-test
├── lib
│ ├── app-1.jar
│ └── app-2.jar
├── Test.class
└── Test.java

测试类 Test:

1
2
3
4
5
6
7
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.xtuer.Aloha");
Object obj = clazz.newInstance();
System.out.println(obj);
}
}

测试用例

结论: 在 classpath 中,即使有多个路径完全相同的类也没问题,JVM 只会加载最先找到的类,忽略其他同名的类:

运行 Test 时,在 classpath 中加载 app-1.jar 和 app-2.jar,使用了 2 种加载方式:

  • jar 包各自的路径
  • 通配符 * 选中所有 jar

jar 包各自的路径:

1
2
3
4
5
6
7
8
9
10
11
D:\temp\jar-test>java -cp .;lib/app-1.jar Test
Aloha-1

D:\temp\jar-test>java -cp .;lib/app-2.jar Test
Aloha-2

D:\temp\jar-test>java -cp .;lib/app-1.jar;lib/app-2.jar Test
Aloha-1

D:\temp\jar-test>java -cp .;lib/app-2.jar;lib/app-1.jar Test
Aloha-2

通配符 * 选中所有 jar:

1
2
3
4
5
6
7
8
9
10
11
# jar 包的名字不变
D:\temp\jar-test>java -cp .;lib/* Test
Aloha-1

# 把 app-1.jar 重命名为 app-3.jar
D:\temp\jar-test>java -cp .;lib/* Test
Aloha-2

# 把 app-3.jar 重命名为 app-13.jar
D:\temp\jar-test>java -cp .;lib/* Test
Aloha-1

提示:

  • 使用 *,不能使用 *.jar
  • 使用 lib/* 只能查找 lib 目录下的 jar,不能递归查找 lib 子目录下的 jar
  • 使用 lib/* 时,哪个 jar 排在前面由系统对文件排序决定