JAVA - 值傳遞與不存在的引用傳遞

概念

pass-by-value(按值傳遞):方法調用時,傳遞參數會在內存中開闢新的空間來存儲參數,實際參數把它的值傳遞給對應的形式參數,函數接收的是原始值的一個copy此時內存中存在兩個相同的變量,即實際參數和形式參數,後面方法中的操作都是對形參這個值的修改,不影響實際參數的值離開函數體,不影響參數本身

pass-by-reference(引用傳遞):引用傳遞,則方法接收的是調用者提供的實際參數的地址每次傳遞變量時,直接傳遞棧地址,而不做複製方法體內和外指向同一個內存空間,裏面改外面也會變

背景知識

基本數據類型值就直接保存在變量中;對引用類型,變量中保存的只是實際對象的地址一般稱這種變量爲"引用",引用指向實際對象,實際對象中保存着內容


JAVA中的值傳遞與引用傳遞

JAVA中只存在值傳遞

JAVA程序設計語言總是採用值調用。也就是說,方法得到的是所有參數值的一個拷貝,特別是,方法不能修改傳遞給它的任何參數變量的內容

* 對基本類型byte,short,int,long,float,double,char,boolean,char)的函數參數傳遞是值傳遞,一個方法是不可能修改一個基本數據類型的參數

public class Test {
	
	private static int x=10;  
    
    public static void updateValue(int value){  
        value = 3 * value;  
    }  
      
    public static void main(String[] args) {  
        System.out.println("調用前x的值:"+x);  
        updateValue(x);  
        System.out.println("調用後x的值:"+x);  
    }
}

運行結果

調用前x的值:10

調用後x的值:10

執行過程:


分析:

value被初始化爲x值的一個拷貝(也就是10);value被乘以3後等於30,但注意此時x的值仍爲10;這個方法結束後,參數變量value不再使用,被回收

* 對於非基本類型(數組,類,接口)的函數參數傳遞傳遞的是對象引用的拷貝,即傳遞的是引用變量內存儲的對象內容的地址值,所以還是按值傳遞

對於引用類型的變量而言,它們的“內容”存放在託管堆裏,而在線程棧裏存放的是“內容”的“地址”。如對象在託管堆中的地址是x0001,那麼棧地址0001的內存空間中存放的就是這個對象的內存地址x0001

:當傳遞方法參數類型爲引用數據類型時,一個方法不修改引用變量本身,但可以修改一個引用數據類型的參數所指向對象的值

public class Test {	
	private static User user=null;  
    public static void updateUser(User student){  
        student.setName("Lishen");  
        student.setAge(18);  
    }  
            
    public static void main(String[] args) {  
        user = new User("zhangsan",26);  
        System.out.println("調用前user的值:"+user.toString());  
        updateUser(user);  
        System.out.println("調用後user的值:"+user.toString());  
    } 
}

class User {  
    private String name;  
    private int age;
    
    public User(String name, int age) {  
        this.name=name;  
        this.age=age;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public int getAge() {  
        return age;  
    }  
    public void setAge(int age) {  
        this.age = age;  
}  

    @Override
    public String toString() {
    	return "Name: " + name + "    Age: " + age;
    }
}

運行結果

調用前user的值:Name: zhangsan    Age: 26

調用後user的值:Name: Lishen    Age: 18

執行過程:

分析:

student變量被初始化爲引用user值的拷貝;調用student變量的set方法作用在這個引用的對象上,user和student同時引用的User對象內部值被修改;方法結束後,student變量不再使用,被釋放,而user還是沒有變,依然指向User對象

public class Test {	
	private static User user=null;  
    private static User stu=null;  
      
    public static void swap(User x,User y){  
        User temp =x;  
        x=y;  
        y=temp;  
    }        
      
    public static void main(String[] args) {  
        user = new User("user",26);  
        stu = new User("stu",18);  
        System.out.println("調用前user的值:"+user.toString());  
        System.out.println("調用前stu的值:"+stu.toString());  
        swap(user,stu);  
        System.out.println("調用後user的值:"+user.toString());  
        System.out.println("調用後stu的值:"+stu.toString());  
    }  
}

運行結果

調用前user的值:Name: user    Age: 26

調用前stu的值:Name: stu    Age: 18

調用後user的值:Name: user    Age: 26

調用後stu的值:Name: stu    Age: 18

執行過程:

分析:

swap方法的參數x和y被初始化爲兩個對象引用的拷貝,這個方法交換的是這兩個拷貝的值而已,最終在方法結束後x,y將被丟棄,而原來的變量user和stu仍然引用這個方法調用之前所引用的對象。這個過程也充分說明了JAVA對對象採用的不是引用調用,而是對象引用進行的是值傳遞,一個方法是不可能修改參數本身的。

* 不可變類String\Integer\Double等

不可變類因爲沒有提供自身修改的函數,創建後,一旦更改等於是重新開了一塊內存地址新生成一個對象

public static void change(String string2){
        string2="zhangsan";
    }
    
    public static void main(String[] args) {
        String string1=new String("abcd");
        System.out.println(string1);
        change(string1);
        System.out.println(string1);
    }

運行結果:

abcd

abcd

分析:

調用change函數後,兩個字符串指向同一個Heap上的地址string2修改內容後指向了新地址,但是string1仍然指向原地址


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章