Java編譯期常量與運(yùn)行時(shí)常量的區(qū)別詳解
引言
在Java開發(fā)中,“常量”是我們每天都會(huì)接觸的概念——從接口超時(shí)時(shí)間、業(yè)務(wù)枚舉值,到全局配置參數(shù),常量的合理使用能提升代碼可讀性、可維護(hù)性,甚至優(yōu)化程序性能。但很多同學(xué)只知道用final修飾常量,卻分不清「編譯期常量」和「運(yùn)行時(shí)常量」的本質(zhì)區(qū)別。
比如:同樣是static final修飾的變量,為什么有的能直接被引用而不觸發(fā)類初始化?有的修改后必須重新編譯所有引用類?有的加了transient卻無效?
一、什么是Java常量?
Java中的常量,本質(zhì)是「初始化后不可修改的變量」,核心約束由final關(guān)鍵字實(shí)現(xiàn)——final修飾的變量,一旦完成初始化,就無法重新賦值(基礎(chǔ)類型不可改值,引用類型不可改引用地址)。
根據(jù)「值確定的時(shí)機(jī)」,常量被分為兩大類型:編譯期常量(Compile-time Constant)和運(yùn)行時(shí)常量(Run-time Constant),二者的底層實(shí)現(xiàn)、使用規(guī)則、性能表現(xiàn)差異極大,也是面試中常被深挖的考點(diǎn)。
補(bǔ)充:Oracle官方文檔明確規(guī)定,常量的核心判定標(biāo)準(zhǔn)是「值是否能在編譯階段確定」,這也是區(qū)分兩種常量的核心依據(jù),后續(xù)所有知識(shí)點(diǎn)都圍繞這一核心展開。
二、編譯期常量(Compile-time Constant)—— 編譯期確定值
2.1 定義與核心特征
編譯期常量,指的是「在Java代碼編譯階段就能確定其最終值」的常量,無需等到程序運(yùn)行,編譯器就能明確其具體值,并對(duì)其進(jìn)行優(yōu)化(如常量折疊)。
核心特征(必須同時(shí)滿足,缺一不可):
- 修飾符:必須用
static final共同修飾(接口中的字段默認(rèn)被public static final修飾,因此接口中的常量默認(rèn)都是編譯期常量); - 數(shù)據(jù)類型:只能是「基本數(shù)據(jù)類型」(byte、short、int、long、float、double、boolean、char)或「String類型」,不能是引用類型(如Integer、Object、數(shù)組等);
- 初始化值:必須是「編譯期可計(jì)算的常量表達(dá)式」,不能依賴運(yùn)行時(shí)的計(jì)算結(jié)果(如方法調(diào)用、new對(duì)象、隨機(jī)值等);
- 底層存儲(chǔ):編譯后,常量值會(huì)直接嵌入到調(diào)用類的字節(jié)碼中,同時(shí)存入方法區(qū)的運(yùn)行時(shí)常量池,無需在運(yùn)行時(shí)從原類中讀??;
- 類初始化:訪問編譯期常量時(shí),不會(huì)觸發(fā)其所在類的初始化(因?yàn)橹狄言诰幾g期確定,無需加載類即可獲?。?。
2.2 合法與非法示例
合法示例(滿足所有條件,屬于編譯期常量):
// 1. 基本類型字面量(最常見)
public static final int MAX_AGE = 100;
public static final boolean FLAG = true;
public static final char CH = 'A';
public static final double PI = 3.1415926;
// 2. String字面量
public static final String NAME = "Java常量";
// 3. 編譯期可計(jì)算的表達(dá)式(僅包含編譯期常量和合法運(yùn)算符)
public static final int SUM = 10 + 20; // 編譯期計(jì)算為30
public static final String COMBINE = "Hello" + "World"; // 編譯期拼接為"HelloWorld"
public static final int DIFF = MAX_AGE - 50; // 引用其他編譯期常量計(jì)算
public static final boolean LOGIC = FLAG && true; // 邏輯運(yùn)算(不包含instanceof、++/--)
// 4. 接口中的常量(默認(rèn)public static final)
interface Constant {
String URL = "https://xxx.com"; // 編譯期常量
int TIMEOUT = 3000;
}非法示例(不滿足條件,不屬于編譯期常量):
// 1. 引用類型(即使是包裝類、枚舉,也不是編譯期常量) public static final Integer NUM = 100; // Integer是引用類型,排除 public static final List<String> LIST = new ArrayList<>(); // 引用類型,排除 public static final EnumType TYPE = EnumType.A; // 枚舉是引用類型,排除 // 2. 初始化值依賴運(yùn)行時(shí)計(jì)算 public static final int RANDOM = new Random().nextInt(); // 運(yùn)行時(shí)隨機(jī)值,排除 public static final String UUID = UUID.randomUUID().toString(); // 方法調(diào)用,運(yùn)行時(shí)確定 public static final int CURRENT_TIME = (int) System.currentTimeMillis(); // 運(yùn)行時(shí)獲取時(shí)間 // 3. 缺少static修飾(僅final修飾,無法成為編譯期常量) public final int AGE = 20; // 僅final,無static,屬于運(yùn)行時(shí)常量 // 4. 使用非法運(yùn)算符(++/--)的表達(dá)式 public static final int COUNT = 10++; // ++是運(yùn)行時(shí)自增,編譯期無法計(jì)算,報(bào)錯(cuò)
2.3 底層原理:編譯期優(yōu)化(常量折疊)
編譯器對(duì)編譯期常量有一個(gè)核心優(yōu)化:常量折疊(Constant Folding)—— 編譯階段,將所有涉及編譯期常量的表達(dá)式直接計(jì)算出結(jié)果,并用結(jié)果替換原表達(dá)式,減少運(yùn)行時(shí)的計(jì)算開銷,提升程序性能。
舉個(gè)例子,看如下代碼:
public class CompileConstant {
public static final int A = 5;
public static final int B = 10;
public static final int C = A * B + 1; // 表達(dá)式:5*10+1
}編譯后,反編譯字節(jié)碼會(huì)發(fā)現(xiàn),C 的值已經(jīng)被直接替換為 51,原表達(dá)式 A * B + 1 會(huì)被編譯器刪除。也就是說,運(yùn)行時(shí)程序直接使用 51,無需再計(jì)算表達(dá)式,這就是常量折疊的優(yōu)化效果。
補(bǔ)充:字符串拼接的優(yōu)化的也是同理,"Hello" + "World" 會(huì)在編譯期直接拼接為"HelloWorld",運(yùn)行時(shí)無需執(zhí)行字符串拼接操作。
2.4 關(guān)鍵特性:訪問不觸發(fā)類初始化
這是編譯期常量最核心的特性,也是面試高頻考點(diǎn)—— 因?yàn)榫幾g期常量的值已經(jīng)嵌入到調(diào)用類的字節(jié)碼中,訪問時(shí)無需加載其所在的類,因此不會(huì)觸發(fā)類的初始化(不會(huì)執(zhí)行靜態(tài)代碼塊、靜態(tài)變量初始化等操作)。
示例:
// 常量類
public class ConstantClass {
// 編譯期常量
public static final String COMPILE_CONST = "編譯期常量";
// 靜態(tài)代碼塊(類初始化時(shí)執(zhí)行)
static {
System.out.println("ConstantClass 被初始化了");
}
}
// 測(cè)試類
public class Test {
public static void main(String[] args) {
// 訪問編譯期常量
System.out.println(ConstantClass.COMPILE_CONST);
}
}運(yùn)行結(jié)果:僅輸出 編譯期常量,不會(huì)輸出 ConstantClass 被初始化了。
原因:訪問編譯期常量時(shí),JVM無需加載 ConstantClass,直接從當(dāng)前類的字節(jié)碼中獲取常量值,因此不會(huì)觸發(fā)類的初始化。
三、運(yùn)行時(shí)常量(Run-time Constant)—— 運(yùn)行期確定值
3.1 定義與核心特征
運(yùn)行時(shí)常量,指的是「在程序運(yùn)行階段(類加載或?qū)ο髮?shí)例化時(shí))才能確定其最終值」的常量,編譯階段無法確定具體值,編譯器無法對(duì)其進(jìn)行常量折疊等優(yōu)化。
核心特征(滿足任意一條即可,無需同時(shí)滿足):
- 修飾符:可以僅用
final修飾(實(shí)例常量),也可以用static final修飾(但初始化值依賴運(yùn)行時(shí)計(jì)算); - 數(shù)據(jù)類型:可以是基本類型、String類型,也可以是引用類型(如Integer、Object、數(shù)組、枚舉等);
- 初始化值:依賴運(yùn)行時(shí)的計(jì)算結(jié)果,如方法調(diào)用、new對(duì)象、讀取配置文件、隨機(jī)值等;
- 底層存儲(chǔ):實(shí)例常量(僅final修飾)跟隨對(duì)象存儲(chǔ)在堆內(nèi)存中;靜態(tài)運(yùn)行時(shí)常量(static final修飾)存儲(chǔ)在方法區(qū)的運(yùn)行時(shí)常量池,但值是運(yùn)行時(shí)確定的;
- 類初始化:訪問靜態(tài)運(yùn)行時(shí)常量時(shí),會(huì)觸發(fā)其所在類的初始化(因?yàn)樾枰\(yùn)行時(shí)確定值,必須加載類);實(shí)例運(yùn)行時(shí)常量需實(shí)例化對(duì)象后才能訪問,會(huì)觸發(fā)對(duì)象初始化。
3.2 常見示例
// 1. 僅final修飾的實(shí)例常量(運(yùn)行時(shí)常量)
public class RuntimeConstant {
// 實(shí)例常量,每次new對(duì)象時(shí)初始化,值可不同
public final int INSTANCE_CONST;
// 構(gòu)造方法中初始化(運(yùn)行時(shí)確定值)
public RuntimeConstant(int value) {
this.INSTANCE_CONST = value;
}
}
// 2. static final修飾,但初始化值依賴運(yùn)行時(shí)計(jì)算
public class RuntimeConstant2 {
// 運(yùn)行時(shí)常量:值由方法調(diào)用確定(運(yùn)行時(shí)計(jì)算)
public static final int RANDOM_NUM = new Random().nextInt(100);
// 運(yùn)行時(shí)常量:值從配置文件讀?。ㄟ\(yùn)行時(shí)加載)
public static final String CONFIG_VALUE = readConfig("config.key");
// 運(yùn)行時(shí)常量:引用類型(枚舉)
public static final EnumType TYPE = EnumType.B;
// 運(yùn)行時(shí)常量:包裝類(引用類型)
public static final Integer WRAP_NUM = 100;
// 靜態(tài)代碼塊(訪問時(shí)會(huì)觸發(fā)執(zhí)行)
static {
System.out.println("RuntimeConstant2 被初始化了");
}
// 讀取配置文件的方法(運(yùn)行時(shí)執(zhí)行)
private static String readConfig(String key) {
// 模擬讀取配置文件
return "config_value";
}
}
// 3. 局部final變量(運(yùn)行時(shí)常量)
public class RuntimeConstant3 {
public void test() {
// 局部final變量,方法執(zhí)行時(shí)初始化,屬于運(yùn)行時(shí)常量
final int LOCAL_CONST = 100;
// 局部final變量,值由參數(shù)確定(運(yùn)行時(shí)傳入)
final String LOCAL_STR = new String("局部常量");
}
}3.3 關(guān)鍵特性:訪問觸發(fā)類/對(duì)象初始化
與編譯期常量相反,運(yùn)行時(shí)常量的值需要在運(yùn)行時(shí)確定,因此訪問時(shí)會(huì)觸發(fā)對(duì)應(yīng)的初始化操作:
- 靜態(tài)運(yùn)行時(shí)常量(static final修飾):訪問時(shí)會(huì)觸發(fā)其所在類的初始化(執(zhí)行靜態(tài)代碼塊、靜態(tài)變量初始化);
- 實(shí)例運(yùn)行時(shí)常量(僅final修飾):需要先new對(duì)象(觸發(fā)對(duì)象初始化),才能訪問該常量。
實(shí)戰(zhàn)驗(yàn)證(延續(xù)上面的示例):
public class Test {
public static void main(String[] args) {
// 訪問靜態(tài)運(yùn)行時(shí)常量,觸發(fā)類初始化
System.out.println(RuntimeConstant2.RANDOM_NUM);
}
}運(yùn)行結(jié)果:
RuntimeConstant2 被初始化了 45(隨機(jī)值,每次運(yùn)行可能不同)
原因:RANDOM_NUM 是靜態(tài)運(yùn)行時(shí)常量,值由 new Random().nextInt(100) 確定(運(yùn)行時(shí)計(jì)算),因此訪問時(shí)必須加載 RuntimeConstant2 類,觸發(fā)類初始化,執(zhí)行靜態(tài)代碼塊。
四、編譯期常量與運(yùn)行時(shí)常量 核心區(qū)別
為了方便大家記憶和對(duì)比,整理了一張?jiān)敿?xì)的對(duì)比表,覆蓋定義、修飾符、底層、性能、初始化等核心維度,同時(shí)補(bǔ)充實(shí)戰(zhàn)中的關(guān)鍵差異:
對(duì)比維度 | 編譯期常量 | 運(yùn)行時(shí)常量 |
核心定義 | 編譯階段確定值,編譯器可優(yōu)化 | 運(yùn)行階段確定值,編譯器無法優(yōu)化 |
修飾符要求 | 必須是 | 可僅 |
數(shù)據(jù)類型 | 僅基本類型 + String類型 | 基本類型、String、引用類型(枚舉、包裝類等)均可 |
初始化值要求 | 編譯期可計(jì)算的常量表達(dá)式(字面量、合法運(yùn)算) | 可依賴運(yùn)行時(shí)計(jì)算(方法調(diào)用、new對(duì)象、配置讀取等) |
底層存儲(chǔ) | 值嵌入調(diào)用類字節(jié)碼,同時(shí)存入運(yùn)行時(shí)常量池 | 靜態(tài):運(yùn)行時(shí)常量池;實(shí)例:堆內(nèi)存 |
類初始化觸發(fā) | 訪問時(shí)不觸發(fā)所在類初始化 | 靜態(tài):訪問時(shí)觸發(fā)類初始化;實(shí)例:new對(duì)象時(shí)觸發(fā) |
編譯器優(yōu)化 | 支持常量折疊,減少運(yùn)行時(shí)開銷 | 無優(yōu)化,運(yùn)行時(shí)計(jì)算值 |
transient修飾效果 | 無效(編譯期常量會(huì)被直接嵌入字節(jié)碼,不受transient影響) | 有效(引用類型的運(yùn)行時(shí)常量,加transient可排除序列化) |
修改后影響范圍 | 修改后需重新編譯所有引用類(否則引用舊值) | 修改后僅需重新編譯自身類,引用類無需重新編譯 |
典型使用場(chǎng)景 | 全局固定值(如PI、接口地址、枚舉字面量) | 動(dòng)態(tài)配置(如配置文件讀取、隨機(jī)值、對(duì)象唯一標(biāo)識(shí)) |
編譯期常量:編譯時(shí)確定值,不觸發(fā)類初始化,可優(yōu)化,修改需全量編譯;
運(yùn)行時(shí)常量:運(yùn)行時(shí)確定值,觸發(fā)初始化,無優(yōu)化,修改僅需編譯自身。
五、如何選擇兩種常量?
很多開發(fā)者濫用static final,導(dǎo)致出現(xiàn)“常量修改后不生效”“類初始化異常”等問題,核心是沒選對(duì)常量類型。結(jié)合企業(yè)級(jí)開發(fā)實(shí)踐,給出明確的選型建議:
5.1 優(yōu)先使用編譯期常量的場(chǎng)景
- 值固定不變,且在編譯期就能確定(如數(shù)學(xué)常量、固定的業(yè)務(wù)基準(zhǔn)值、接口固定地址);
- 需要被多個(gè)類引用,且希望減少運(yùn)行時(shí)開銷(常量折疊優(yōu)化,提升性能);
- 不需要觸發(fā)類初始化(如工具類中的常量,避免不必要的類加載)。
示例:工具類中的常量定義
public class MathUtil {
// 編譯期常量:固定不變,可優(yōu)化
public static final double PI = 3.1415926;
public static final int DEFAULT_SCALE = 2;
public static final String EMPTY_STR = "";
}5.2 優(yōu)先使用運(yùn)行時(shí)常量的場(chǎng)景
- 值需要?jiǎng)討B(tài)確定(如從配置文件讀取、數(shù)據(jù)庫查詢、隨機(jī)生成、方法返回值);
- 常量是引用類型(如枚舉、包裝類、數(shù)組、對(duì)象);
- 每個(gè)對(duì)象需要獨(dú)立的常量值(如對(duì)象的唯一標(biāo)識(shí)、實(shí)例級(jí)別的固定配置);
- 常量值可能會(huì)修改,且不想重新編譯所有引用類(降低維護(hù)成本)。
示例:配置類中的運(yùn)行時(shí)常量
public class ConfigConstant {
// 運(yùn)行時(shí)常量:從配置文件讀取(動(dòng)態(tài)確定值)
public static final String DB_URL = ConfigLoader.load("db.url");
public static final int DB_PORT = Integer.parseInt(ConfigLoader.load("db.port"));
// 運(yùn)行時(shí)常量:引用類型(枚舉)
public static final DataSourceType DATA_SOURCE_TYPE = DataSourceType.MYSQL;
// 實(shí)例運(yùn)行時(shí)常量:每個(gè)對(duì)象獨(dú)立值
public final String INSTANCE_ID;
public ConfigConstant(String instanceId) {
this.INSTANCE_ID = instanceId;
}
}六、注意事項(xiàng)
1:誤以為“static final修飾的都是編譯期常量”
錯(cuò)誤認(rèn)知:只要用static final修飾,就是編譯期常量。
錯(cuò)誤示例:
// 錯(cuò)誤:認(rèn)為這是編譯期常量,實(shí)際是運(yùn)行時(shí)常量 public static final Integer NUM = 100; public static final String UUID = UUID.randomUUID().toString();
原因:Integer是引用類型,UUID的值由方法調(diào)用確定(運(yùn)行時(shí)),因此這兩個(gè)都是運(yùn)行時(shí)常量,訪問時(shí)會(huì)觸發(fā)類初始化,且不支持常量折疊。
正確做法:判斷是否為編譯期常量,不僅看修飾符,還要看「數(shù)據(jù)類型」和「初始化值是否可編譯期確定」。
2:編譯期常量修改后,引用類未重新編譯,導(dǎo)致舊值殘留
場(chǎng)景:類A定義了編譯期常量MAX_NUM = 100,類B引用了A.MAX_NUM;修改A類的MAX_NUM = 200,僅重新編譯A類,未編譯B類,運(yùn)行時(shí)B類仍使用舊值100。
原因:編譯期常量的值會(huì)嵌入到引用類的字節(jié)碼中,B類編譯后,字節(jié)碼中已經(jīng)是100,修改A類后,若不重新編譯B類,B類會(huì)一直使用嵌入的舊值。
避坑方案:修改編譯期常量后,必須重新編譯所有引用該常量的類;若常量值可能頻繁修改,建議改為運(yùn)行時(shí)常量(從配置文件讀?。?。
3:用transient修飾編譯期常量,誤以為能排除序列化
錯(cuò)誤示例:
public class SerializeTest implements Serializable {
// 錯(cuò)誤:transient修飾編譯期常量,無效
private transient static final String SECRET = "123456";
}原因:編譯期常量會(huì)被直接嵌入字節(jié)碼,序列化時(shí)不受transient影響,即使加了transient,序列化后仍能獲取到常量值。
正確做法:若想排除常量的序列化,不要用transient(對(duì)編譯期常量無效),可實(shí)現(xiàn)Externalizable接口,手動(dòng)控制不寫入該字段。
4:局部final變量誤認(rèn)為是編譯期常量
錯(cuò)誤示例:
public void test() {
final int a = new Random().nextInt();
// 錯(cuò)誤:認(rèn)為a是編譯期常量,實(shí)際是運(yùn)行時(shí)常量
System.out.println(a + 10);
}原因:局部final變量的初始化值若依賴運(yùn)行時(shí)計(jì)算,就是運(yùn)行時(shí)常量,編譯器無法對(duì)其進(jìn)行常量折疊優(yōu)化;只有局部final變量的初始化值是字面量或編譯期可計(jì)算表達(dá)式,才會(huì)被編譯器優(yōu)化。
5:接口中的常量不是編譯期常量
錯(cuò)誤示例:
interface MyConstant {
// 錯(cuò)誤:認(rèn)為這是編譯期常量,實(shí)際是運(yùn)行時(shí)常量
String CONFIG = readConfig();
static String readConfig() {
return "config";
}
}原因:接口中的常量默認(rèn)是public static final,但初始化值readConfig()是方法調(diào)用(運(yùn)行時(shí)確定),因此是運(yùn)行時(shí)常量,訪問時(shí)會(huì)觸發(fā)接口的初始化。
七、全文總結(jié)
1. 兩種常量的核心區(qū)別:值確定的時(shí)機(jī)(編譯期 vs 運(yùn)行期);
2. 編譯期常量:static final + 基本/String + 編譯期表達(dá)式,不觸發(fā)類初始化,支持常量折疊;
3. 運(yùn)行時(shí)常量:可僅final,支持引用類型,值依賴運(yùn)行時(shí)計(jì)算,觸發(fā)初始化;
4. 坑點(diǎn)核心:不要混淆static final和編譯期常量,修改編譯期常量需全量編譯;
5. 選型原則:固定值用編譯期,動(dòng)態(tài)值用運(yùn)行期;
6. 面試關(guān)鍵:類初始化觸發(fā)、常量折疊、transient效果、修改后影響范圍。
編譯期常量與運(yùn)行時(shí)常量,看似簡(jiǎn)單,卻藏著JVM底層優(yōu)化和開發(fā)細(xì)節(jié),也是大廠面試中區(qū)分“初級(jí)開發(fā)者”和“中級(jí)開發(fā)者”的關(guān)鍵考點(diǎn)。
很多開發(fā)者因?yàn)榉植磺宥?,?dǎo)致出現(xiàn)“常量修改不生效”“類初始化異常”“序列化漏洞”等問題,看完這篇,基本能避開所有高頻坑,同時(shí)應(yīng)對(duì)所有相關(guān)面試題。
以上就是Java編譯期常量與運(yùn)行時(shí)常量的區(qū)別詳解的詳細(xì)內(nèi)容,更多關(guān)于Java編譯期常量與運(yùn)行時(shí)常量的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Eclipse 導(dǎo)出可執(zhí)行Java工程/可執(zhí)行Jar文件(包含第三方Jar包)
這篇文章主要介紹了Eclipse 導(dǎo)出可執(zhí)行Java工程/可執(zhí)行Jar文件(包含第三方Jar包)的相關(guān)資料,需要的朋友可以參考下2016-11-11
新建springboot項(xiàng)目時(shí),entityManagerFactory報(bào)錯(cuò)的解決
這篇文章主要介紹了新建springboot項(xiàng)目時(shí),entityManagerFactory報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
如何自定義springboot-starter日志組件供各個(gè)服務(wù)使用(系統(tǒng)日志優(yōu)化)
文章介紹了如何將各個(gè)微服務(wù)的接口調(diào)用日志邏輯優(yōu)化為一個(gè)可共享的Spring Boot Starter,通過自定義注解和自動(dòng)裝配機(jī)制實(shí)現(xiàn),本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2025-01-01
Java實(shí)現(xiàn)限定時(shí)間CountDownLatch并行場(chǎng)景
本文將結(jié)合實(shí)例代碼,介紹Java實(shí)現(xiàn)限定時(shí)間CountDownLatch并行場(chǎng)景,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07
工廠模式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了工廠模式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理的相關(guān)資料,需要的朋友可以參考下2017-08-08
淺談MySQL中是如何實(shí)現(xiàn)事務(wù)提交和回滾的
本文主要介紹了MySQL中是如何實(shí)現(xiàn)事務(wù)提交和回滾的,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
java多線程編程之向線程傳遞數(shù)據(jù)的三種方法
在多線程的異步開發(fā)模式下,數(shù)據(jù)的傳遞和返回和同步開發(fā)模式有很大的區(qū)別。由于線程的運(yùn)行和結(jié)束是不可預(yù)料的,因此,在傳遞和返回?cái)?shù)據(jù)時(shí)就無法象函數(shù)一樣通過函數(shù)參數(shù)和return語句來返回?cái)?shù)據(jù)2014-01-01
關(guān)于通過java調(diào)用datax,返回任務(wù)執(zhí)行的方法
今天小編就為大家分享一篇關(guān)于通過java調(diào)用datax,返回任務(wù)執(zhí)行的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-08-08
Java參數(shù)校驗(yàn)詳解之使用@Valid注解和自定義注解進(jìn)行參數(shù)驗(yàn)證
在后端開發(fā)中,參數(shù)校驗(yàn)是非常普遍的,下面這篇文章主要給大家介紹了關(guān)于Java參數(shù)校驗(yàn)詳解之使用@Valid注解和自定義注解進(jìn)行參數(shù)驗(yàn)證的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06

