Java類(lèi)加載器ClassLoader詳解
以下文章都是基于JDK1.8環(huán)境
一、類(lèi)的加載過(guò)程
JDK8引用的都是jar包

JDK11引用的都是model

我們編寫(xiě)的".java"文件需要通過(guò)javac編譯成".class"文件,而程序運(yùn)行時(shí),JVM會(huì)把".class"文件加載到內(nèi)存中,并創(chuàng)建對(duì)應(yīng)的class對(duì)象,這個(gè)過(guò)程被稱(chēng)為類(lèi)的加載。
簡(jiǎn)單來(lái)說(shuō):將class文件讀入內(nèi)存,并為之創(chuàng)建一個(gè)Class對(duì)象。
JVM運(yùn)行的是class文件,不單單是java語(yǔ)言,無(wú)論哪種語(yǔ)言編寫(xiě)的,只要文件是.class類(lèi)型的,就能夠在JVM上運(yùn)行。
學(xué)習(xí)類(lèi)加載器的目的:使用類(lèi)加載器可以讓我們得代碼7*24小時(shí),不間斷地運(yùn)行。即修改代碼后無(wú)需重啟就能生效,類(lèi)似于熱部署。

二、默認(rèn)的類(lèi)加載器
JVM通過(guò)類(lèi)加載器把“.class”文件加載到內(nèi)存中,默認(rèn)有 3 個(gè)類(lèi)加載器,分別是:
- Bootstrap ClassLoader 啟動(dòng)類(lèi)加載器
- ExtClassLoader 擴(kuò)展類(lèi)加載器
- AppClassLoader 系統(tǒng)類(lèi)加載器(應(yīng)用類(lèi)加載器)
三個(gè)類(lèi)加載器各有不同的作用
(一)Bootstrap ClassLoader1.基本介紹
作用:加載JDK核心類(lèi)庫(kù)(String,Integer,Long,ArrayList等等)
方式:加載某個(gè)類(lèi)時(shí),在指定的路徑中(Jar包或文件夾)搜索這個(gè)類(lèi),如果搜到就加載,如果沒(méi)搜到,報(bào):ClassNotFoundException
搜索路徑:由 sun.boot.class.path 所指定的,比如:%JRE_HOME%\jre\lib下的rt.jar、resources.jar、charsets.jar等,也就是JDK核心類(lèi)庫(kù),其中 rt.jar 里面就存放著常用的 JAVA API

代碼演示:
public static void main(String[] args) {
// 輸出String類(lèi)是被哪個(gè)類(lèi)加載器,加載到內(nèi)存中
System.out.println(String.class.getClassLoader());
// 獲取系統(tǒng)配置
// bootstrap生效的時(shí)候會(huì)去sun.boot.class.path路徑下找對(duì)應(yīng)的類(lèi)
String paths = System.getProperty("sun.boot.class.path");
// windows下使用;分隔
// linux使用:分隔
String[] arr = paths.split(";");
for (String s : arr) {
System.out.println(s);
}
}返回結(jié)果:

為什么String.class.getClassLoader() 返回null?
原因是:Bootstrap ClassLoader是由C/C++編寫(xiě)的,是虛擬機(jī)的一部分,并不是JAVA中的類(lèi),所以無(wú)法在 Java 代碼中獲取它的引用,因此返回 null。
因此:如果一個(gè)類(lèi)(System.out.println(String.class.getClassLoader());)輸出為null,說(shuō)明該類(lèi)是被Bootstrap ClassLoader加載的。前提是基于JDK1.8環(huán)境。
Bootstrap ClassLoader加載String類(lèi)會(huì)去下面這些類(lèi)中尋找:

最后一行不是默認(rèn)路徑,是IDEA默認(rèn)添加的,紅框部分才是默認(rèn)加載路徑。
String類(lèi)在rt包下,按照上圖的順序依次向下找,在rt包中找到后,就不會(huì)繼續(xù)向下尋找了。
2.自定義路徑
可通過(guò) -Xbootclasspath 參數(shù)修改 Bootstrap ClassLoader 的搜索路徑
用法 | 含義 | 備注 |
-Xbootclasspath:路徑 | 指定的路徑會(huì)完全取代jdk核心的搜索路徑 | 堅(jiān)決不要用 |
-Xbootclasspath/a:路徑 | 指定的路徑會(huì)在jdk核心類(lèi)后搜索 | 可用 |
-Xbootclasspath/p:路徑 | 指定的路徑會(huì)在jdk核心類(lèi)前搜索 | 可用,不建議使用 |
注意:如果配置多個(gè)路徑,linux/unix下用“:”分割,windows下用“;”分割。
代碼演示:在 pom.xml 中添加 commons-io,同時(shí)也要把這個(gè)jar包放到D:\test 中
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.8.0</version>
</dependency>
添加JVM參數(shù),指定尋找的包路徑在jdk核心類(lèi)后搜索
-Xbootclasspath/a:D:\test\commons-io-2.8.0.jar

去這個(gè)包下尋找ByteOrderMark這個(gè)類(lèi)

修改代碼:
public static void main(String[] args) {
// 輸出String類(lèi)是被哪個(gè)類(lèi)加載器,加載到內(nèi)存中
// System.out.println(String.class.getClassLoader());
System.out.println(ByteOrderMark.class.getClassLoader());
// 獲取系統(tǒng)配置
// bootstrap生效的時(shí)候會(huì)去sun.boot.class.path路徑下找對(duì)應(yīng)的類(lèi)
String paths = System.getProperty("sun.boot.class.path");
// windows下使用;分隔
// linux使用:分隔
String[] arr = paths.split(";");
for (String s : arr) {
System.out.println(s);
}
}運(yùn)行結(jié)果:

Bootstrap ClassLoader在JDK核心類(lèi)中找不到就會(huì)去指定的路徑下尋找。
(二)ExtClassLoader
1.基本使用
擴(kuò)展類(lèi)加載器,加載擴(kuò)展類(lèi)庫(kù),搜索路徑由-Djava.ext.dirs指定,比如:%JRE_HOME%\jre\lib\ext目錄下的jar包和class文件。即ExtClassLoader加載類(lèi)的時(shí)候會(huì)去下面的路徑尋找,找不到就會(huì)報(bào)錯(cuò)。

代碼演示:
public static void main(String[] args) {
// 輸出String類(lèi)是被哪個(gè)類(lèi)加載器,加載到內(nèi)存中
// System.out.println(String.class.getClassLoader());
// System.out.println(ByteOrderMark.class.getClassLoader());
System.out.println(DNSNameService.class.getClassLoader());
// 獲取系統(tǒng)配置
// 輸出 ExtClassLoader 掃描的路徑,注意:輸出的是文件夾
String paths = System.getProperty("java.ext.dirs");
// windows下使用;分隔
// linux使用:分隔
String[] arr = paths.split(";");
for (String s : arr) {
System.out.println(s);
}
}運(yùn)行結(jié)果:

sun.misc.Launcher$ExtClassLoader@383534aa
有$符號(hào)表示ExtClassLoader是Launcher這個(gè)類(lèi)的內(nèi)部類(lèi)。只要出現(xiàn)$就說(shuō)明后面是前面的內(nèi)部類(lèi)
搜索ExtClassLoader后,發(fā)現(xiàn)ExtClassLoader確實(shí)是個(gè)內(nèi)部類(lèi),并且還是靜態(tài)的。


2.配置指定路徑
-Djava.ext.dirs=D:\test

public static void main(String[] args) {
// 輸出String類(lèi)是被哪個(gè)類(lèi)加載器,加載到內(nèi)存中
// System.out.println(String.class.getClassLoader());
System.out.println(ByteOrderMark.class.getClassLoader());
// System.out.println(DNSNameService.class.getClassLoader());
// 獲取系統(tǒng)配置
// 輸出 ExtClassLoader 掃描的路徑,注意:輸出的是文件夾
String paths = System.getProperty("java.ext.dirs");
// windows下使用;分隔
// linux使用:分隔
String[] arr = paths.split(";");
for (String s : arr) {
System.out.println(s);
}
}代碼中表示,讓ExtClassLoader去D:\test文件夾下尋找ByteOrderMark這個(gè)類(lèi)。
運(yùn)行結(jié)果:

自定義路徑會(huì)把默認(rèn)路徑覆蓋掉,所以這種方法不建議使用,了解即可。
(三)AppClassLoader
AppClassLoader也叫SystemClassLoader(系統(tǒng)類(lèi)加載器),搜索路徑由java.class.path(CLASSPATH) 指定。加載項(xiàng)目中自己寫(xiě)的類(lèi) 和 第三方依賴包。
public static void main(String[] args) {
// 輸出String類(lèi)是被哪個(gè)類(lèi)加載器,加載到內(nèi)存中
// System.out.println(String.class.getClassLoader());
// System.out.println(ByteOrderMark.class.getClassLoader());
// System.out.println(DNSNameService.class.getClassLoader());
System.out.println(Main.class.getClassLoader());
// 獲取系統(tǒng)配置
// 輸出 ExtClassLoader 掃描的路徑,注意:輸出的是文件夾
String paths = System.getProperty("java.class.path");
// windows下使用;分隔
// linux使用:分隔
String[] arr = paths.split(";");
for (String s : arr) {
System.out.println(s);
}
}運(yùn)行結(jié)果:

最下面的兩行是IDEA自帶的,無(wú)需理會(huì)

由此可以看出,IDEA在運(yùn)行java代碼時(shí),主動(dòng)給我們添加了很多路徑(JDK核心類(lèi)庫(kù)、擴(kuò)展類(lèi)庫(kù)、自己寫(xiě)的類(lèi)和第三方依賴包到classpath中),所以才會(huì)打印如此多的路徑。如下圖。

(四)類(lèi)加載器的初始化
1.源碼跟蹤
從上面的輸出可以發(fā)現(xiàn) ExtClassLoader、AppClassLoader都是 Java 對(duì)象,接下來(lái)看一下它們是如何創(chuàng)建的。
這兩個(gè)對(duì)象的生成都是在 Launcher 中完成的:Launcher類(lèi)是 java 程序的入口,在啟動(dòng) java 應(yīng)用的時(shí)候會(huì)首先創(chuàng)建Launcher類(lèi)的對(duì)象,創(chuàng)建Launcher類(lèi)的時(shí)候會(huì)創(chuàng)建ExtClassLoader、AppClassLoader。
Launcher類(lèi)太過(guò)于底層,所以無(wú)法打斷點(diǎn),構(gòu)造方法如下:
首先,創(chuàng)建 ExtClassLoader


ExtClassLoader對(duì)象創(chuàng)建成功后,將器傳入AppClassLoader中

點(diǎn)進(jìn)這個(gè)getAppClassLoader靜態(tài)方法:

super一直點(diǎn)到最上層,在這里,parent參數(shù)就是傳入的 ExtClassLoader。
由此可以看出:ExtClassLoader是AppClassLoader的父類(lèi)加載器。

2.ExtClassLoader和AppClassLoader的關(guān)系結(jié)論——父類(lèi)加載器
在 Java 中,AppClassLoader 和 ExtClassLoader 都是由 sun.misc.Launcher 類(lèi)創(chuàng)建的。盡管它們的名字中包含“ClassLoader”,但它們并不是通過(guò)繼承關(guān)系來(lái)定義父子關(guān)系的,而是通過(guò)設(shè)置父加載器的方式來(lái)實(shí)現(xiàn)的。這意味著 AppClassLoader 實(shí)際上是將 ExtClassLoader 作為其父類(lèi)加載器,而不是通過(guò)類(lèi)繼承的方式。
只有類(lèi)之間才會(huì)存在繼承關(guān)系,我們這里說(shuō)的是AppClassLoader 和 ExtClassLoader對(duì)象。
在 Java 類(lèi)加載器的上下文中,“父類(lèi)加載器”這個(gè)術(shù)語(yǔ)并不意味著類(lèi)加載器之間存在繼承關(guān)系(即它們不是通過(guò) extends 關(guān)鍵字定義的父子類(lèi)關(guān)系),而是指類(lèi)加載器之間的委派關(guān)系。具體來(lái)說(shuō),AppClassLoader 將 ExtClassLoader 作為其父類(lèi)加載器,指的是當(dāng) AppClassLoader 需要加載某個(gè)類(lèi)時(shí),它首先會(huì)請(qǐng)求 ExtClassLoader(它的父類(lèi)加載器)嘗試加載該類(lèi)。這種機(jī)制是基于“雙親委派模型”的。
因此,AppClassLoader的父類(lèi)是URLClassLoader;父類(lèi)加載器是ExtClassLoader。


通過(guò)debug可以看出來(lái),AppClassLoader的parent屬性是ExtClassLoader,ExtClassLoader的parent屬性是BootstrapClassLoader,前文提過(guò),顯示null,就說(shuō)明是BootstrapClassLoader。

三、雙親委派模式
(一)概念介紹
雙親委派模式是Java類(lèi)加載機(jī)制的核心原理,用于規(guī)范類(lèi)加載器之間的協(xié)作方式。其核心思想是:當(dāng)一個(gè)類(lèi)加載器收到類(lèi)加載請(qǐng)求時(shí),不會(huì)直接自己加載,而是將請(qǐng)求委派給父類(lèi)加載器,只有當(dāng)父類(lèi)加載器無(wú)法加載時(shí),才會(huì)由當(dāng)前類(lèi)加載器自己嘗試加載。
如果父加載器可以完成加載任務(wù),就成功返回;倘若父加載器無(wú)法完成此加載任務(wù),子加載器才會(huì)嘗試自己去加載。

(二)源碼解釋
加載一個(gè)類(lèi),一定先從 Launcher.AppClassLoader 的 loadClass 方法開(kāi)始。
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
// 1. 檢查是否已加載
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
// 2. 委派給父類(lèi)加載器(遞歸向上)
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// 父類(lèi)加載器未找到,繼續(xù)執(zhí)行
}
if (c == null) {
// 3. 自己嘗試加載
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}(三)雙親委派模式的核心優(yōu)勢(shì)
- 安全性:確保核心類(lèi)(如java.lang.Object)只能由啟動(dòng)類(lèi)加載器加載,防止用戶自定義類(lèi)覆蓋JDK核心類(lèi),避免惡意代碼篡改。保證java核心api不會(huì)被隨意替換,專(zhuān)業(yè)說(shuō)法:沙箱安全機(jī)制。
- 唯一性:同一名稱(chēng)的類(lèi)只會(huì)被加載一次(由首個(gè)能加載它的類(lèi)加載器完成),確保類(lèi)實(shí)例的兼容性。
- 層級(jí)隔離:不同類(lèi)加載器加載的類(lèi)空間隔離,例如Tomcat的多個(gè)Web應(yīng)用可通過(guò)不同類(lèi)加載器隔離類(lèi)版本。
代碼示例:
自定義一個(gè)Integer類(lèi):
package java.lang;
public class Integer {
public static void main(String[] args) {
System.out.println("運(yùn)行自定義的Integer類(lèi)......");
}
}運(yùn)行結(jié)果:

原因是BootStrap ClassLoader已經(jīng)在核心類(lèi)庫(kù)中找到j(luò)ava.lang.Integer類(lèi)了,所以不會(huì)再加載自定義的java.lang.Integer類(lèi)了,這充分體現(xiàn)了JDK核心類(lèi)不會(huì)被覆蓋的優(yōu)勢(shì)。
四、動(dòng)態(tài)加載
(一)URLClassLoader
URLClassLoader是Java中用于從指定的URL(統(tǒng)一資源定位符)加載類(lèi)和資源的類(lèi)加載器,屬于java.lang.ClassLoader的子類(lèi),也是ExtClassLoader和AppClassLoader的父類(lèi)。它允許從網(wǎng)絡(luò)或本地文件系統(tǒng)中的目錄、JAR 文件等位置動(dòng)態(tài)加載類(lèi),廣泛應(yīng)用于插件化開(kāi)發(fā)、熱部署、動(dòng)態(tài)模塊加載等場(chǎng)景。
常用的構(gòu)造方法:
- URLClassLoader(URL[] urls, ClassLoader parent):使用指定的父加載器創(chuàng)建對(duì)象,從指定的urls路徑來(lái)查詢、并加載類(lèi)。
- URLClassLoader(URL[] urls):使用默認(rèn)的父加載器(AppClassLoader)創(chuàng)建一個(gè)ClassLoader對(duì)象,從指定的urls路徑來(lái)查詢、并加載類(lèi)。
(二)實(shí)戰(zhàn)
新建一個(gè)普通的java項(xiàng)目parse-excel-demo,并打成jar包。

在另一個(gè)項(xiàng)目classloader-demo中編寫(xiě)下面的代碼,即可使用上面的方法
public class RunDemo {
public static void main(String[] args) throws Exception {
File file = new File(
"G:\\develop\\workspace\\four\\" +
"newSmProjects\\parse-excel-demo\\target\\" +
"parse-excel-demo-1.0-SNAPSHOT.jar");
URL[] urls = {file.toURI().toURL()};
URLClassLoader myUrlClassLoader = new URLClassLoader(urls);
Class<?> parseExcel = myUrlClassLoader.loadClass("com.test.excel.ParseExcel");
Object obj = parseExcel.newInstance();
Method parse = parseExcel.getMethod("parse");
parse.invoke(obj);
}
}運(yùn)行結(jié)果:

即使被引用的jar包內(nèi)容被修改,只要路徑正確,RunDemo所在的項(xiàng)目都不需要重啟就能運(yùn)行:

RunDemo運(yùn)行結(jié)果:

(三)依賴問(wèn)題
有些時(shí)候,parse-excel-demo中可能引用一些第三方庫(kù),比如:jackson-core-2.11.0.jar
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.11.0</version> </dependency>
并在代碼中使用:
package com.test.excel;
import com.fasterxml.jackson.core.JsonFactory;
public class ParseExcel {
public void parse() {
System.out.println("開(kāi)始解析Excel......");
JsonFactory jsonFactory = new JsonFactory();
System.out.println("運(yùn)行其getFormatGeneratorFeatures方法:" +
jsonFactory.getFormatGeneratorFeatures());
}
}修改后重新對(duì) parse 打包,然后運(yùn)行clasterloader-demo中的代碼,結(jié)果:

問(wèn)題分析:
myUrlClassLoader的父類(lèi)加載器是


場(chǎng)景 | 父類(lèi)加載器 | 原因 |
|---|---|---|
默認(rèn)構(gòu)造URLClassLoader(urls) | AppClassLoader | 默認(rèn)使用系統(tǒng)類(lèi)加載器作為父類(lèi)加載器。 |
顯式指定父類(lèi)加載器 | 任意(如ExtClassLoader) | 可通過(guò)構(gòu)造方法URLClassLoader(urls,parent)自定義。 |
繼承關(guān)系 | URLClassLoader是父類(lèi) | AppClassLoader和ExtClassLoader是URLClassLoader的子類(lèi)。 |
根據(jù)雙親委派模式,myUrlClassLoader加載時(shí)parseExcel的時(shí)候會(huì)去加載JsonFactory,加載JsonFactory會(huì)交給父類(lèi)加載器AppClassLoader,AppClassLoader無(wú)法加載就會(huì)交給其父類(lèi)加載器ExtClassLoader,ExtClassLoader無(wú)法加載又交給自己的父類(lèi)加載器BootStrap ClassLoader,都找不到才會(huì)報(bào)錯(cuò)。
因此,當(dāng)我們開(kāi)發(fā)中碰到ClassNotFoundException的排錯(cuò)方法要考慮類(lèi)的加載過(guò)程。
解決方案:完善代碼,將JsonFactory所屬的包放在myUrlClassLoader的掃描路徑下:
public class RunDemo {
public static void main(String[] args) throws Exception {
File file = new File(
"G:\\develop\\workspace\\four\\" +
"newSmProjects\\parse-excel-demo\\target\\" +
"parse-excel-demo-1.0-SNAPSHOT.jar");
File file2 = new File(
"D:\\apache-maven-3.8.1\\repository\\" +
"com\\fasterxml\\jackson\\core\\jackson-core\\2.11.0" +
"\\jackson-core-2.11.0.jar");
URL[] urls = {file.toURI().toURL(), file2.toURI().toURL()};
URLClassLoader myUrlClassLoader = new URLClassLoader(urls);
Class<?> parseExcel = myUrlClassLoader.loadClass("com.test.excel.ParseExcel");
Object obj = parseExcel.newInstance();
Method parse = parseExcel.getMethod("parse");
parse.invoke(obj);
}
}

也可以將依賴放入classloader-demo中。AppClassLoader可以成功加載第三方依賴包。
(四)版本沖突問(wèn)題
我們降低classloader-demo中的依賴版本:

再次運(yùn)行會(huì)報(bào)錯(cuò):

即使將2.11.0版本放到搜索路徑中還是會(huì)報(bào)錯(cuò),因?yàn)锳ppClassLoader已經(jīng)加載完畢了,myUrlClassLoader就不會(huì)再加載了。

而項(xiàng)目中已有的依賴也不能更改,那么如何解決呢?
讓程序同時(shí)運(yùn)行兩個(gè)版本的jsonFactory即可。
public class RunDemo {
public static void main(String[] args) throws Exception {
File file = new File(
"G:\\develop\\workspace\\four\\" +
"newSmProjects\\parse-excel-demo\\target\\" +
"parse-excel-demo-1.0-SNAPSHOT.jar");
File file2 = new File(
"D:\\apache-maven-3.8.1\\repository\\" +
"com\\fasterxml\\jackson\\core\\jackson-core\\2.11.0" +
"\\jackson-core-2.11.0.jar");
URL[] urls = {file.toURI().toURL(),file2.toURI().toURL()};
// 創(chuàng)建自定義類(lèi)加載器
// 這時(shí)候myUrlClassLoader的parent是ExtClassLoader
URLClassLoader myUrlClassLoader = new URLClassLoader(urls,RunDemo.class.getClassLoader().getParent());
Class<?> parseExcel = myUrlClassLoader.loadClass("com.test.excel.ParseExcel");
Object obj = parseExcel.newInstance();
Method parse = parseExcel.getMethod("parse");
parse.invoke(obj);
}
}
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- java通過(guò)URLClassLoader類(lèi)加載器加載外部jar代碼示例
- Java類(lèi)加載器之ContextClassLoader詳解
- Java中的ClassLoader類(lèi)加載器使用詳解
- Java ClassLoader類(lèi)加載器基礎(chǔ)詳解
- Java類(lèi)加載器ClassLoader的使用詳解
- Java類(lèi)加載器ClassLoader源碼層面分析講解
- jvm之java類(lèi)加載機(jī)制和類(lèi)加載器(ClassLoader)的用法
- Java類(lèi)加載器ClassLoader用法解析
- classloader類(lèi)加載器_基于java類(lèi)的加載方式詳解
相關(guān)文章
SpringAop實(shí)現(xiàn)原理及代理模式詳解
Spring的AOP就是通過(guò)動(dòng)態(tài)代理實(shí)現(xiàn)的,使用了兩個(gè)動(dòng)態(tài)代理,分別是JDK的動(dòng)態(tài)代理和CGLIB動(dòng)態(tài)代理,本文重點(diǎn)給大家介紹下SpringAop實(shí)現(xiàn)原理及代理模式,感興趣的朋友一起看看吧2022-04-04
springbooot整合dynamic?datasource數(shù)據(jù)庫(kù)密碼加密方式
這篇文章主要介紹了springbooot整合dynamic?datasource?數(shù)據(jù)庫(kù)密碼加密方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
使用lombok@Data存在extends時(shí)需要注意的問(wèn)題
在Java編程中,正確實(shí)現(xiàn)equals方法是保證對(duì)象比較一致性的關(guān)鍵,使用instanceof檢查類(lèi)型可能導(dǎo)致違反對(duì)稱(chēng)性原則,即當(dāng)子類(lèi)和父類(lèi)都重寫(xiě)equals時(shí)可能出現(xiàn)a.equals(b)不等于b.equals(a)的情況,Lombok的@EqualsAndHashCode注解可以通過(guò)callSuper=true參數(shù)2024-10-10
Java中增強(qiáng)for循環(huán)在一維數(shù)組和二維數(shù)組中的使用方法
下面小編就為大家?guī)?lái)一篇Java中增強(qiáng)for循環(huán)在一維數(shù)組和二維數(shù)組中的使用方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10
JDBC中PreparedStatement詳解以及應(yīng)用場(chǎng)景實(shí)例介紹
PreparedStatement對(duì)象代表的是一個(gè)預(yù)編譯的SQL語(yǔ)句,用它提供的setter方法可以傳入查詢的變量,這篇文章主要給大家介紹了關(guān)于JDBC中PreparedStatement詳解以及應(yīng)用場(chǎng)景實(shí)例介紹的相關(guān)資料,需要的朋友可以參考下2024-02-02
httpclient ConnectionHolder連接池連接保持源碼解析
這篇文章主要為大家介紹了httpclient ConnectionHolder連接池連接保持源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
springboot security自定義認(rèn)證過(guò)程
這篇文章主要介紹了springboot security自定義認(rèn)證過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03

