Java傳值調(diào)用和傳引用調(diào)用方式(參數(shù)引用為null問(wèn)題)
一、問(wèn)題
近期在項(xiàng)目中遇到一個(gè)場(chǎng)景,在多層級(jí)調(diào)用中需要傳遞上下文,調(diào)用過(guò)程中上線文對(duì)象可能為空,想通過(guò)一個(gè)公共方法處理上下文,當(dāng)上下文為空時(shí)生成上下文對(duì)象,執(zhí)行相關(guān)操作后將該上下文對(duì)象向后傳遞。
大致邏輯如下:
public class Test {
public static void handleContext(Context context) {
if(context == null) {
context = new Context();
}
context.addNum();
}
public static void main(String[] args) {
Context context = null;
handleContext(context);
System.out.println(context.getNum());
}
static class Context {
private int num;
public int getNum() {
return num;
}
public void addNum() {
this.num ++;
}
}
}測(cè)試執(zhí)行報(bào)空指針錯(cuò)誤,context沒(méi)有按設(shè)想在handleContext方法中生成對(duì)象。
原因是main方法在棧中創(chuàng)建了Context的引用并將其指向null,handleContext方法參數(shù)中的Context引用也被指向null,handleContext方法體在堆中創(chuàng)建Context對(duì)象,并將對(duì)象地址賦給方法參數(shù)中的Context引用,但main方法中的Context引用仍然為null,因此調(diào)用context.getNum()時(shí)報(bào)空指針。
二、java方法傳值與傳引用
2.1 變量存儲(chǔ)
基礎(chǔ)類(lèi)型變量:
Java的8中基礎(chǔ)數(shù)據(jù)類(lèi)型:byte(8位)、short(16位)、int(32位)、long(64位)、float(32位)、double(64位)、char(16位)、boolean(8位),
基礎(chǔ)類(lèi)型的數(shù)據(jù)存儲(chǔ)在棧中,即是棧中分配內(nèi)存空間存儲(chǔ)所包含的值,其值就代表數(shù)據(jù)本身,值類(lèi)型的數(shù)據(jù)具有較快的存取速度。
引用類(lèi)型變量:
除了基礎(chǔ)類(lèi)數(shù)據(jù)外,其余都是引用類(lèi)型,包括類(lèi)、數(shù)組等。
引用類(lèi)型數(shù)據(jù)的具體對(duì)象存放在堆中,而棧中存放的是該對(duì)象的內(nèi)存地址。
當(dāng)引用類(lèi)型沒(méi)有賦值時(shí),其引用為null,表示不指向任何對(duì)象。
2.2 創(chuàng)建對(duì)象與賦值過(guò)程
Context context = new Context();
該操作可以分為兩個(gè)部分:
Context context; context = new Context();
第一步:創(chuàng)建Context引用,在棧中開(kāi)辟一塊空間用于存儲(chǔ)該引用;
第二步:創(chuàng)建Context對(duì)象,在堆內(nèi)存中開(kāi)辟一塊空間存儲(chǔ)該對(duì)象,并將該對(duì)象的存儲(chǔ)地址賦值給棧中的引用
2.3 引用賦值過(guò)程
將一個(gè)引用賦值給另一個(gè)引用時(shí),其實(shí)是將該引用指向的地址賦值給另個(gè)應(yīng)用,讓兩個(gè)引用指向同一個(gè)對(duì)象,示意圖如下。
Context context1 = new Context(); Context context2 = context1;

2.4 傳值與傳引用方法調(diào)用
其實(shí)無(wú)論是傳值還是傳引用調(diào)用,其本質(zhì)都是將棧中存儲(chǔ)的數(shù)據(jù)復(fù)制一份,傳遞給棧中的另一個(gè)變量。
對(duì)于基礎(chǔ)數(shù)據(jù)類(lèi)型,是將數(shù)據(jù)本身復(fù)制一份傳遞;對(duì)于引用類(lèi)型,是將引用的地址復(fù)制一份傳遞。
因此,上述問(wèn)題可以描述為如下示意圖。當(dāng)handleContext方法執(zhí)行返回后,main方法中的context引用仍然為null。
注:為方便理解,將null特殊處理。當(dāng)引用為null時(shí)候表示不指向任何對(duì)象

值得注意的是包裝類(lèi)型(Intger;Long;Short;Double;Float;Char;Boolean;Byte,以及String(char[]的包裝類(lèi)型)),雖然是引用類(lèi)型數(shù)據(jù),但其效果等同于傳值調(diào)用,示例如下:
public class Test {
public static void change(String str) {
str = "xyz";
}
public static void main(String[] args) {
String str = "abc";
change(str);
System.out.println(str);
}
}
---
abc其原因是String類(lèi)型是不可變(immutable)的。
String類(lèi)型及其成員變量均是final的,這意味著String的value字符數(shù)組不能指向其它地址,同時(shí)value字符數(shù)組的值也不可能通過(guò)繼承String后修改。
在change方法中,參數(shù)String引用str初始化時(shí)指向?qū)ο骯bc,執(zhí)行方法后指向了方法區(qū)的另一個(gè)字符串常量(xyz),而main方法中的String引用str仍然指向方法區(qū)的字符串常量(abc)。
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
...
private final char value[];
...
}2.5 Java常量池
基本類(lèi)型的包裝類(lèi)型大部分都實(shí)現(xiàn)了常量池技術(shù),包括:Byte、Short、Integer、Long、Character、Boolean,但只有在其值 -128<value<127范圍內(nèi)才可使用常量池,數(shù)據(jù)存放在方法區(qū),數(shù)值超出范圍或通過(guò)new方法生成對(duì)象則會(huì)在堆上分配存儲(chǔ)空間
public class Test {
public static void main(String[] args) {
Integer i = 123;
Integer j = 123;
System.out.println("i == j : " + (i == j));
System.out.println("i.equals(j) : " + i.equals(j));
Integer m = 1234;
Integer n = 1234;
System.out.println("m == n : " + (m == n));
System.out.println("m.equals(n) : " + m.equals(n));
Integer x = new Integer(123);
Integer y = new Integer(123);
System.out.println("x == y : " + (x == y));
System.out.println("x.equals(y) : " + x.equals(y));
}
}
---
i == j : true
i.equals(j) : true
m == n : false
m.equals(n) : true
x == y : false
x.equals(y) : true總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java使用Hashtable過(guò)濾數(shù)組中重復(fù)值的方法
這篇文章主要介紹了java使用Hashtable過(guò)濾數(shù)組中重復(fù)值的方法,涉及java數(shù)組遍歷及過(guò)濾的相關(guān)技巧,需要的朋友可以參考下2016-08-08
基于Java SSM實(shí)現(xiàn)Excel數(shù)據(jù)批量導(dǎo)入
這篇文章主要為大家詳細(xì)介紹了基于Java SSM如何實(shí)現(xiàn)excel數(shù)據(jù)批量導(dǎo)入,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11
SpringBoot 2.0 整合sharding-jdbc中間件實(shí)現(xiàn)數(shù)據(jù)分庫(kù)分表
這篇文章主要介紹了SpringBoot 2.0 整合sharding-jdbc中間件,實(shí)現(xiàn)數(shù)據(jù)分庫(kù)分表,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-06-06
Java LongAdder原理解析與實(shí)戰(zhàn)應(yīng)用小結(jié)
LongAdder是Java 8中java.util.concurrent.atomic包引入的高性能計(jì)數(shù)器類(lèi),專(zhuān)為高并發(fā)場(chǎng)景下的數(shù)值累加操作優(yōu)化設(shè)計(jì),本文給大家介紹Java LongAdder原理解析與實(shí)戰(zhàn)應(yīng)用小結(jié),感興趣的朋友一起看看吧2025-06-06
實(shí)例解析Java設(shè)計(jì)模式編程中的適配器模式使用
本篇文章主要通過(guò)實(shí)例對(duì)適配器模式進(jìn)行了詳解,需要的朋友可以參考下2017-04-04
Java微信公眾平臺(tái)開(kāi)發(fā)(2) 微信服務(wù)器post消息體的接收
這篇文章主要為大家詳細(xì)介紹了Java微信公眾平臺(tái)開(kāi)發(fā)第二步,微信服務(wù)器post消息體的接收,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
解決IDEA2020.1.2IDEA打不開(kāi)的問(wèn)題(最新分享)
由于idea安裝多了某個(gè)jar,點(diǎn)擊出現(xiàn)讀條后閃退情況,接下來(lái)通過(guò)本文給大家分享解決IDEA2020.1.2IDEA打不開(kāi)的問(wèn)題,非常不錯(cuò),具有一定的參考借鑒價(jià)值,感興趣的朋友跟隨小編一起看看吧2020-07-07

