1. 程式人生 > >Java物件記憶體儲存,引用傳遞,值傳遞詳細圖解

Java物件記憶體儲存,引用傳遞,值傳遞詳細圖解

問題:
Java在呼叫函式時,物件作為引數傳遞,執行函式後引數物件的值是否發生改變。
正文:
在解決這個問題之前首先得說說Java物件在記憶體中的儲存機制。
我們知道Java資料型別基本分為兩種,一是基本型別,還一種是引用型別。
基本型別:
物件型別是固定的,如下:
byte,short,int,long,float,double,char,boolean
並且被建立後的值是存放在記憶體棧空間中。
引用型別:
除了以上8種資料型別的資料物件都是引用資料物件,一般來說就是我們自定義的類的物件(如Person類,Info類等)。
其建立後的值是存放記憶體的堆空間中的,在棧空間中只存有該物件的引用。
圖解說明:
1,基本型別
這裡寫圖片描述


2,引用型別
這裡寫圖片描述

那麼接下來再分析,Java在函式呼叫時,引數傳遞的過程。
我們知道函式本身也是放在棧空間中的,呼叫函式後函式體內部將為形參開闢空間。
1,基本型別做形參函式呼叫

int a = 100;
public void add_self(int x)
{
    x = x + x;
}
log.i("tag",a);

這裡寫圖片描述
經過上圖分析,add_self函式中只對內部變數x地址中的值產生了改變,而a變數指向地址的值一直沒有傳送改變,所以函式結束後log打印出來的還是100;

當然如果有返回型別的這種,那情況就不一樣了。

int a = 100;
public int add_self
(int x) { return x = x + x; } a = add_self(a); log.i("tag",a);

這裡寫圖片描述
這種情況基本同上,只是函式最後一步將x地址中的值傳遞出來了,並且a變數接收了,那麼實質上就是a變數ox0008地址區域中的值被重新賦值為x變數中的值,故函式結束後a值傳送改變。log輸出200。
2,引用型別做形參函式呼叫
經過開始的分析我們知道,在棧中引用型別物件地址空間中存放的只是一段指向堆空間的地址值。那麼在引數傳遞的過程中本質和基本型別引數傳遞是一樣的。都是將函式外部物件的值傳遞給函式體中物件,然後在函式體內部做的任何操作與外部物件的地址都無關。(注意這是是說外部物件地址,但是其引用堆中的物件卻不一定)。

Person p = new Person();
p.name = "小明";
p.sex = "boy";

public void changePerson(Person person)
{
    person.name = "小輝";
    p.sex = "boy";
}

changePerson(p);
log.i("tag",p.name);

這裡寫圖片描述
接下來再看函式體中對person物件進行操作後,記憶體中資料的變化情況。
這裡寫圖片描述
函式執行完成後,堆中的值卻發生改變了,整個函式操作間接的對p物件的值造成了影響。故log出來的是“小輝”。
從這裡就可以看出,基本型別與引用型別在引數傳遞中的本質是一樣的,都是屬於值傳遞!但是由於引用型別物件的資料存放在堆中,而且函式中可以改變堆中的值。故導致他們作為引數傳遞的結果又不一樣。但是萬變不離其宗,根據記憶體分析還是很容易理解的。

同理這裡有沒有返回值都沒什麼影響了,如果函式有return,並且被p物件接收,p物件中存放的還是ox8008地址。如果沒有return ,p物件中存放的值任然是ox8008。
PS:當在函式體中對形參變數重新引用了別的物件,那麼情況是這樣的。

public void changePerson(Person person)
{
    Person p1 = new Person();
    p1.name = "小花";
    person = p1;
}
public void changePerson2(Person person)
{
    person = new Person();
    person.name = "小花";
}

這兩種情況的本質都是改變了函式內部person物件的引用物件。
這裡寫圖片描述
所以在person物件指向別的引用後,其對屬性發生的任何改變都對p物件無關。除非函式有返回值,且讓p物件指向person物件的引用空間。

總結:
1,基本型別物件存放在棧中,引用型別物件資料存放在堆中。
2,無論是基本型別物件還是引用型別物件,作為引數傳入函式中本質都是值傳遞。
3,判讀一個物件的值是否傳送改變,關鍵是看其本身的值,如果是引用物件則要看其值引向的堆空間的值。

相關推薦

Java物件記憶體儲存引用傳遞傳遞詳細圖解

問題: Java在呼叫函式時,物件作為引數傳遞,執行函式後引數物件的值是否發生改變。 正文: 在解決這個問題之前首先得說說Java物件在記憶體中的儲存機制。 我們知道Java資料型別基本分為兩種,一是基本型別,還一種是引用型別。 基本型別: 物件型別

討論java中呼叫函式形參的傳遞傳遞還是引用傳遞的問題

首先說結論: 當引數是引用資料型別時,傳入形參的是實參的引用;(證一) 當引數是基本資料型別時,傳入形參的是實參值;(證二) 證明如下: (證一) public class PassByReferenceOrValueTest { public static void main(String

Java千百問_05面向物件(011)_引用傳遞傳遞有什麼區別

1、什麼是值傳遞 值傳遞,是將記憶體空間中某個儲存單元中存放的值,傳送給另一個儲存單元。(java中的儲存單元並不是實體記憶體的地址,但具有相關性) 例如: //定義了一個改變引數值的函式 public static void changeVa

python 引用傳遞傳遞(實參形參)

python中函式引數是引用傳遞(不是值傳遞)。對於不可變型別,因變數不能被修改,所以運算時不會影響到變數本身;而對於可變型別來說,函式體中的運算有可能會更改傳入的引數變數.形參: 函式需要傳遞的引數實參:呼叫函式時傳遞的引數

C++中函式引數傳遞傳遞、指標傳遞引用傳遞

今天想寫一個函式,從函式中把我需要的兩個值傳出來,由於傳出來的值比較多,所以不考慮用return來返回,需要通過引數把修改後的值拉出來供我使用,很當然的就想到了用指標,但是值就是傳不出來;使我對原有的大腦中指標的思維產生混沌感,今天一上午才把函式傳遞又走了

為什麼拷貝建構函式必須為引用傳遞不能是傳遞

對於拷貝建構函式引用傳遞,似乎司空見慣,認為理所當然。但是被問起這個問題,的確是一片茫然,為什麼呢?去網上搜索了一下,的確有很多這方面的知識講解。我們先看一下CSDN上的一個帖子的回答:簡單的回答是為了防止遞迴引用。具體一些可以這麼講: 當 一個物件需要以值方式傳遞時,編譯器會生成程式碼呼叫它的拷貝建構函式以

java+pgsql實現儲存圖片到資料庫以及讀取資料庫儲存的圖片

1 /** 2 * 3 */ 4 package com.hlcui.file; 5 6 import java.io.FileInputStream; 7 import java.io.InputStream; 8 import java.sql.Connection; 9 i

java讀取記憶體中的csv檔案跳過第一行

package ApacheCommonCSV; import junit.framework.TestCase; import org.apache.commons.csv.CSVFormat; im

理解Java中的引用傳遞傳遞

包裝類 pri ble buffer 聲明 change cnblogs padding ber 關於Java傳參時是引用傳遞還是值傳遞,一直是一個討論比較多的話題,有論壇說Java中只有值傳遞,也有些地方說引用傳遞和值傳遞都存在,比較容易讓人迷惑。關於值傳遞和引用傳遞其

Struts2配置使用參數接收轉發與重定向多方法ognl使用與傳遞struts標簽使用

isp -name users .org 填充 導航 建模 尋址 XML 本文檔包括了 Struts2配置使用參數接收,轉發與重定向,多方法,ognl使用與值傳遞,struts標簽使用 (1)首先加入jar包(最小jar組合) (1) 在web.xml中註冊

java 引用傳遞傳遞

方式 con 並不是 一個 基本類型 依賴 tro 結束 事務 1.為什麽要分值傳遞和引用傳遞:   基本類型存在在棧中,復合類型(對象)存在堆中。操作棧的速度要快於堆,且對象的復制相比基本類型不僅浪費內存而且速度比較慢。 從這裏就可以看出來:對象是按照引用傳遞(數據庫事務

java引用傳遞傳遞

pos += 基本 test 特殊 今天 對象類型 改變 ring 關於Java傳參時是引用傳遞還是值傳遞,一直是一個討論比較多的話題,有論壇說Java中只有值傳遞,也有些地方說引用傳遞和值傳遞都存在,比較容易讓人迷惑。關於值傳遞和引用傳遞其實需要分情況看待,今天學習和分析

Java中的引用傳遞傳遞

基本類型包裝類 new except pri 引用類型 otsu 靜態 數據 app   1.基本類型和引用類型在內存中的保存  Java中數據類型分為兩大類,基本類型和對象類型。相應的,變量也有兩種類型:基本類型和引用類型。  基本類型的變量保存原始值,即它代表的值就是數

java引用傳遞還是傳遞

app 分享 jvm內存模型 作用 相同 http thumb 第一個 bject 首先,不要糾結於 Pass By Value 和 Pass By Reference 的字面上的意義,否則很容易陷入所謂的“一切傳引用其實本質上是傳值”這種並不能解決問題無意義論戰中。更何

java 裏面的引用傳遞傳遞問題

system nal 新建 類型 tostring 問題 沒有 引用 操作 1.先從值引用:String a ="God";//a存放在stack 中 God存放在head(堆中)創建了兩個對象String b=a;a指向堆中的God對象b=a;說明b也

python也太自動函式傳遞前會判斷是否要‘傳遞而PHP通通‘傳遞

一、python ​ # 不可變物件 預設值拷貝 # python裡的值拷貝:把不可變物件所引用的值全部拷貝 # 其它語言的值拷貝:不管你是不是可變不可變,通通給你複製一份 def test_unchanged(a): a+=1 a = 1 test_unchanged(a) prin

c++中普通變數引用變數 指標變數用例項讓你親自體會

int a1 = 10; int a2 = 20; int a3 = a1;//賦值語句,可以理解成資料的克隆,a3與a1 不在是指向一個物件 int &b = a1; //int &b2 = 900; //不合法,非常量引用的初始值必須左值 int *c =

C++練習引用本質複雜資料型別示例等

#include <iostream> using namespace std; //第一點 /** int main() {     int a = 10;     int &b = a;   

JAVA基本資料型別、引用資料型別-引數傳遞詳解

1:基本型別的引數傳值 對於基本資料型別,修改這個值並不會影響作為引數傳進來的那個變數,因為你修改的是方法的區域性變數,是一個副本。實參的精度級別應等於或低於形參的精度級別,否則報錯。 class JB{ void f(int x, int y){ x=x+1;

關於java的引數傳遞傳遞引用傳遞和傳、傳引用等)

所謂引數傳遞就是用函式呼叫所給出的實參(實際引數)向函式定義所給出的形參(形式引數)設定初始值的過程。基本的有三種引數分別為: (1)傳值:   (2)傳址(即是傳指標) (3)傳引用 以上