Java只有值傳遞!為什麼?

2021-02-13 Java技術棧

面試官愛問的一個基礎問題:Java是值傳遞還是引用傳遞?

想必大家都對這個問題都有自己的看法,那到底事實是怎樣的,我們又該如何回答面試官這個問題呢?今天咱們就來好好分析一波

值傳遞?引用傳遞?

首先,我們得先知道什麼叫值傳遞,什麼叫引用傳遞,知道這個才能理解Java到底如何做的。若想理解這兩種傳遞需要先理解形式參數和實際參數兩個概念

形式參數: 定義函數時使用的參數,用來接收函數傳入參數,比如我們寫個函數,函數中的參數為形式參數

(String str) { System..println(str)}

實際參數: 我們調用函數時,函數名後面括號中的參數稱為實際參數,如下面例子所示

(String[] args) {
    A a = A()a.test()}

可以發現,當調用一個有參函數的時候,會把實際參數傳遞給形式參數;於是這個傳遞的過程便有兩種情況,即值傳遞和引用傳遞

值傳遞就是把參數的值給你,調用函數時將實際參數複製一份傳遞到函數中,這樣函數內部對參數內部進行修改不會影響到實際參數;而引用傳遞就不一樣了,它直接把參數的實際地址給調用函數了,函數內部可直接修改該地址內容,會影響到實際參數

我來舉個例子,我司有一個資料庫A,僅允許內部人員操作,現在有個項目需要和別的公司合作,該資料庫的數據需要交給合作公司一份,我總不能直接把我司資料庫A地址給他們,讓他們直接連我們資料庫A吧,他們要是刪庫跑路了,那我boss豈不要殺我祭天了

所以這個時候,把我司資料庫表數據拷貝一份到一個新的資料庫B,合作公司可以看這個資料庫B數據,他們也可以隨意操作,不會影響我司資料庫

這個操作就類似於值傳遞,如果合作公司直接操作我司資料庫,就類似於引用傳遞了,這下大家應該曉得兩者之別了

Java值傳遞還是引用傳遞?

我們了解了值傳遞和引用傳遞的概念,那Java中到底是哪種傳遞方式呢?我們來看代碼分析

(String[] args) {
    Fans fans = Fans()t = fans.test(t)System..println(+ t) }

(t) {
    t = System..println(+ t) }

//輸出
In testIn main

上述代碼,在main中定義t的值是1,在函數test中修改了參數t的值為2,這個結果是不是很容易分析出來了呢?test函數並未改變傳入的t的值,那按照上面我們的介紹是不是可以得出結論:Java中是值傳遞

有的人可能會質疑,你傳入的參數t是基本類型,你若傳入引用對象類型,那肯定就會改變對象內容了,OK,再來看一段引用類型代碼

= String = (Fans fans) {
    fans.= fans.= System..println(+ fans.++fans.)}

(String[] args) {
    Fans fa = Fans()fa.test(fa)System..println(+ fans.getA()++fans.getB())}

//輸出

In testABnewFans
In mainABnewFans

哎啊,輸出結果竟然一樣了,也就是傳入的fans對象被函數test修改了,那這樣是不是又變成了引用傳遞了?

於是得出結論,基本類型是值傳遞,引用類型是引用傳遞?事實是這個樣子嗎,我們再來通過String這個引用類型實驗下

(String t) {
    t = System..println(+ t)}

(String[] args) {
    Fans fans = Fans()String tt = fans.test(tt)System..println(+ t)}

//輸出
In test:關注公眾號
In main:Java技術棧

啊,這,咋肥事,傳遞的參數值並未修改,怎麼又變成值傳遞了

上述三個例子表現結果各有差異,到底結論是什麼呢?一起來分析下

第一個傳入的是基本類型,基本類型指向的就是數值,傳遞類似於賦值操作,不會對原數值產生影響,就是類似於a=10,b=a,b=20這種,並不會使a變為20;

第二個引用對象傳入的是引用類型fans的地址的值,傳入的原參數fa指向地址0x123456,所以函數test的參數fans也指向0x123456,函數內部對引用fans進行修改,於是修改了0x123456地址的值,造成外部改變

第三個引用對象是String類型,同樣傳入的是原參數tt的指向地址0x123456,函數test參數t也是指向0x123456的值,那為什麼這個和第二個結果不一樣的嘞?重點在於 t="關注公眾號"; 這一句本來想嘗試著使內容"Java技術棧"改變成"關注公眾號",但是無奈,String類型是static final類型的,這個大家應該曉得的不,不曉得的該去補課讀讀String的源碼了,於是變成了 t=new String("關注公眾號"),t指向了另一個地址,這個地址的內容是"關注公眾號",所以原來的引用tt還是指向原來的地址0x123456,並未改變

有的同學可能會提出問題了,為什麼第二個可以改變這個地址的內容,第三個不行?很明顯啊,String是final的,不可修改,而第二個可以直接修改該地址的內容;那問題又來了,既然這樣,還能叫值傳遞嗎?

告訴你,就是值傳遞,因為我們第二個的驗證方法不對,你如果在函數的第一行加上個fans = new Fans();你看看它還輸出啥,這就變成和第三個String類似的道理了,改變了函數參數的指向位置,函數外部和函數內部輸出就不一樣了,函數內部也就不會影響外部了;如果按照應引用傳遞,即使加了這一句,也應該是函數內外都是輸出一樣的,況且,這也有悖於引用傳遞的會改變傳入參數的概念

思考

值傳遞和引用傳遞並不是按照傳遞的內容來區分的,傳遞的是引用的並不一定的引用傳遞,根據定義結果來區分;

在Java中用的是值傳遞(記好咯,下次面試別回答錯了)

在其它方法裡面改變引用類型的值都是通過引用改變的,當傳遞引用對象的時候,傳遞的是複製的引用的對象句柄,是複製過的,也就是在內存中複製了一個句柄,這兩個句柄指向同一個對象,所以你改變這個句柄對應的空間的數據會影響到外部的變量

雖然是複製的,但是指向的是同一個地址,當你把這個句柄指向其它對象的引用時並不會改變原來的值(例子三String),因為你用的是複製過的句柄

最後嘮叨

贈人玫瑰,手留餘香

如果本文幫助到你了,說明我的下個文章也會幫到你,留個關注吧,麼麼噠

相關焦點

  • 面試官:Java為什麼只有值傳遞?
    Java值傳遞還是引用傳遞?我們了解了值傳遞和引用傳遞的概念,那Java中到底是哪種傳遞方式呢?於是得出結論,基本類型是值傳遞,引用類型是引用傳遞?地址的值,造成外部改變第三個引用對象是String類型,同樣傳入的是原參數tt的指向地址0x123456,函數test參數t也是指向0x123456的值,那為什麼這個和第二個結果不一樣的嘞?
  • Java是按引用傳遞還是按值傳遞
    java對象引用按值傳遞Java中的所有對象引用均按值傳遞。這意味著該值的副本將傳遞給方法。但是訣竅在於傳遞值的副本也會更改對象的實際值。您已經了解到Java變量是通過值傳遞的,這意味著將傳遞值的副本。只要記住複製的值指向Java內存堆中的真實對象即可。按值傳遞仍然會更改實際對象的值。接受對象引用挑戰!在此Java Challenger中,我們將測試您從對象引用中學到的知識。
  • 零基礎java入門教程函數function實例化格式案例void返回值說明
    參數類型:是形參的數據類型;形參:是一個變量,用於存儲調用函數時傳遞給函數的實參;實參:傳遞給形參的具體數值;return:用於結束函數;返回值:該值會返回給調用者;該功能只有被調用才會執行,所以所放源碼位置前後不受影響。
  • Java面試題:如何對HashMap按鍵值排序
    2.創建一個簡單的HashMap,並插入一些鍵和值。 List<Entry<String,Integer>> aList = new LinkedList<Entry<String,Integer>>(mapEntries);5.通過傳遞鍊表和自定義比較器來使用Collections.sort()方法排序鍊表。
  • 值傳遞和引用傳遞傳的到底是啥?
    作者 | 編程指北 責編 | 張文在網上看到過很多討論 Java、C++、Python 是值傳遞還是引用傳遞這類文章,所以這一篇呢就是想從原理講明白關於函數參數傳遞的幾種形式。參數傳遞無外乎就是傳值(pass by value),傳引用(pass by reference)或者說是傳指針。
  • Java方法形參引用傳值問題
    抽取出來的方法參數非常多,如果按照常規的想法,就需要每個參數指定一個返回值,匯總到一個Map中,再將Map作為返回值傳遞出去。那麼問題就來了,這麼多參數,類型有List、Map且較為複雜,如果再用一個Map接收,還需要做數據類型轉換非常的麻煩,可能還會產生新的問題。
  • 為什麼阿里巴巴Java開發手冊強制整型包裝類對象值用equals比較?
    為什麼會緩存這個範圍的賦值?如何學習和分析類似的問題?那麼為什麼答案是這樣?結合《阿里巴巴Java開發手冊》的描述很多人可能會回答:因為緩存了 -128 到 127 之間的數值,就沒有然後了。那麼為什麼會緩存這一段區間的數值?緩存的區間可以修改嗎?其它的包裝類型有沒有類似緩存?
  • Java8 lambda表達式
    匿名內部類是為了讓java程式設計師傳遞行為和傳遞數據一樣容易,不幸的是,他們並不容易,為了調用處理邏輯的代碼仍然有四行模板代碼,重複的模板代碼並不是唯一的問題,這種代碼也難以閱讀,我們並不想傳遞一個對象,而僅僅只需要傳遞某種行為,在java8中我們可以寫得更簡潔不同於傳遞一個實現某個接口的對象,我們傳遞了一段沒有命名函數的代碼
  • 每日一課 | Java –比較枚舉值
    在Java中,可以使用==運算符比較Enum值。
  • java大於127byte值轉int
    因為java沒有無符號數,所以在byte值大於127時,java表達的是負數。例如:byte b = (byte)152;// b的值在java中表達的是:-104,二進位值是:10011000。int i = b;// i 的值 在java中表達的是:-104,二進位值是:11111111111111111111111110011000如果想要 i 的值等於152,需要以下運算:/*** byte轉int,
  • 面試題之java基礎
    2、值傳遞和引用傳遞的區別:答:①值傳遞:值傳遞是將進行傳遞的值進行拷貝,然後對拷貝之後的值進行傳遞,傳遞過程前後不改變原值的大小;②引用傳遞:引用傳遞是將需要傳遞值的地址進行傳遞,傳遞過程前後會改變原值的大小。
  • 【Java面試題】常見Java面試知識點總結-1
    java中也不可以覆蓋private的方法,因為private修飾的變量和方法只能在當前類中使用,如果是其他的類繼承當前類是不能訪問到private變量或方法的,當然也不能覆蓋。4.是否可以在static環境中訪問非static變量?static變量在Java中是屬於類的,它在所有的實例中的值是一樣的。
  • 尚學堂知識整理:java 枚舉值
    級別枚舉類型的變量只能是以下四個值之一 - LOW,MEDIUM,HIGH 和 URGENT 或 null。可以通過使用枚舉類型名稱作為限定符和點符號來引用枚舉常量。以下代碼將Level枚舉類型常量的值分配給一些局部變量:但是不能實例化枚舉類型。
  • Java開發之數據參數傳值應如何傳遞
    前言提到Java開發,常見的開發框架有SSM、SSH,無論是哪種形式,都會用到參數的傳遞,從前臺向後臺傳遞可以通過session、cookie、form表單,從後臺向前臺傳遞可以通過定義變量並設置該變量的get、set方法的方式,還有一種是通過變量
  • 為什麼Java的main方法必須是public static void?
    當然,很多人首先學的是 C 和 C++,但是在 Java 中 main 方法與前者有些細微的不同,它不會返回任何值,為什麼 main 方式是 public、static、void,這篇文章嘗試去找到一些答案。
  • Stackoverflow問答:Java是傳值還是傳引用?
    來自:並發編程網 - ifeve.com原文:http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value
  • 終於明白了Java為什麼要加final關鍵字了!
    below-java8.jpg 但是在 Java 8 之後,類似場景卻沒有再提示了: ,還將基本數據類型的變量複製了一份過來,並把引用數據類型的變量引用也傳遞了過來。
  • 為什麼函數式編程在Java中很危險?
    為什麼函數式編程在Java中很危險呢?每隔幾個月,我都會在調試中發現問題,究其原因最終可追溯到濫用函數的想法以及編程算法,更重要的原因是這個虛擬機無法創建這種編程樣式。Exception in thread "main" java.lang.OutOfMemoryError: Java heap space  at java.util.Arrays.copyOf(Arrays.java:2760)  at java.util.Arrays.copyOf(Arrays.java:2734)  at java.util.ArrayList.ensureCapacity
  • java序列化反序列化中serialVersionUID到底有什麼用
    序列化\反序列化:java序列化是指把java對象轉換為字節序列的過程,而java反序列化是指把字節序列恢復為java對象的過程。;在進程間傳遞對象。實現的必要條件:只有實現了Serializable或Externalizable接口的對象才能被序列化,否則拋出異常。
  • 我來告訴你,為什麼java培訓班出來就業太難
    為什麼java培訓班出來就業太難很多人看中it行業的高薪,高福利,以及未來前景。但是培訓一結束就面臨著就業困難這個問題。其實,我剛開始的時候也是這樣的,在這裡我為大家分析分析現在為什麼java培訓班出來就業難的問題。