為什么說Java中只有值傳遞?


一.為什么說Java中只有值傳遞?

對於java中的參數傳遞方式中是否有引用傳遞這個話題,很多的人都認為Java中有引用傳遞,但是我個人的看法是,Java中只有值傳遞,沒有引用傳遞。

那么關於對象的傳遞怎么解釋呢?難道對象不是一個引用傳遞嗎?

對於這一點我的看法是,對象的傳遞只不過是將對象的地址值傳遞到方法里,只要你不改變這個地址值,那他就指向原來的引用不會改變,但是你一旦改變了這個地址值,那么你就改變了他的實際引用。那歸根到底還不是值傳遞嗎?只不過我普通類型傳遞的是copy后的普通類型的值,我引用傳遞的是一個copy的地址值而已。

當然我在舉例子的時候還是將他們分開:

實際的例子如下:

1.值傳遞

package com.cjm.functionparameter;

/**
 * @author 程嘉明
 * @version 創建時間:2018/8/9 10:18
 * 函數得值傳遞
 */
public class Valuetransmit {
    public static void main(String[] args) {
        int num=0;//定義一個值
        System.out.println("在main中定義的值為:"+num);
        fan(num);
        System.out.println("在調用函數的值為:"+num);
    }
    public static  void fan(int num){
        System.out.println("###########進入函數###########");
        System.out.println("實參為:"+num+"此時的值沒有被改變!");
        //修改函數的參數:
        ++num;
        System.out.println("在函數中實參自增后的值為:"+num);
        System.out.println("###########退出函數###########");
    }
}

可以看出值傳遞是不會改變他本身的值。

所以Java中你就無法使用一個函數將兩個變量的值交換。

嘗試如下:

package com.cjm.functionparameter;

/**
 * @author 程嘉明
 * @version 創建時間:2018/8/9 10:35
 */
public class ChangeValue {
    public static void main(String[] args) {
        //定義兩個變量
        int num1=0;
        int num2=1;
        System.out.println("未經過函數的交換的值為:"+"num1="+num1+"\tnum2="+num2);
        change(num1,num2);
        System.out.println("經過函數的交換后的值為:"+"num1="+num1+"\tnum2="+num2);
    }
    //設置一個”交換函數“
    public static void change(int num1,int num2){
        int temp=num1;
        num1=num2;
        num2=temp;
    }
}

失敗了,Java不能替我們完成這一項任務,但這無傷大雅,因為我們並不想交換兩個變量的值就去定義一個函數,這實在是小題大做了。

2.杠精們的"引用傳遞"

 那么首先我需要一個對象,來檢測一下在函數中的對象是否和外面的對象相同。

package com.cjm.functionparameter;

/**
 * @author 程嘉明
 * @version 創建時間:2018/8/9 10:53
 * 對象的判斷函數實參對象,和傳遞對象是否相同
 */
public class ObjectJudge {
    public static void main(String[] args) {
        A a=new A(0);
        System.out.println("main函數中的對象的哈希值為:"+a.hashCode());
        System.out.println();
        fan(a);
    }
    public static void fan(A a){
        System.out.println("函數中的對象的哈希值為:"+a.hashCode());
    }
}
class A{
    int num;
    public A(int num) {
        this.num = num;
    }
}

 

可以看出這兩個引用指向的對象的哈希值是一樣的,那么也就是說這兩個引用指向的是同一個對象。

那么也是說我們在函數對對象a的操作也會影響外面的對象。

來看下面的操作:

package com.cjm.functionparameter;
/**
 * @author 程嘉明
 * @version 創建時間:2018/8/9 10:53
 * 對象的判斷函數實參對象,和傳遞對象是否相同
 */
public class ObjectJudge {
    public static void main(String[] args) {
        A a=new A(0);
        System.out.println("main函數中的對象的哈希值為:"+a.hashCode());
        System.out.println("在main函數中的對象的num為:"+a.num);
        System.out.println("##########函數開始##########");
        fan(a);
        System.out.println("##########函數之后##########");
        System.out.println("在main函數中的對象的num為:"+a.num);
    }
    public static void fan(A a){
        System.out.println("函數中的對象的哈希值為:"+a.hashCode());
        a.num=10;
        System.out.println("在函數中的對象的num為:"+a.num);
    }
}
class A{
    int num;
    public A(int num) {
        this.num = num;
    }
}

 

那么我們現在再來修改一下,將函數中的對象修改為其他的引用會發生什么

package com.cjm.functionparameter;
/**
 * @author 程嘉明
 * @version 創建時間:2018/8/9 10:53
 * 對象的判斷函數實參對象,和傳遞對象是否相同
 */
public class ObjectJudge {
    public static void main(String[] args) {
        A a=new A(0);
        System.out.println("main函數中的對象的哈希值為:"+a.hashCode());
        System.out.println("在main函數中的對象的num為:"+a.num);
        System.out.println("##########函數開始##########");
        fan(a);
        System.out.println("##########函數之后##########");
        System.out.println("在main函數中的對象的num為:"+a.num);
    }
    public static void fan(A a){
        System.out.println("為做改變前,函數中的對象的哈希值為:"+a.hashCode());
        a=new A(0);
        System.out.println("做了重新賦值后,函數中的對象的哈希值為:"+a.hashCode());
        a.num=10;
        System.out.println("在函數中的對象的num為:"+a.num);
    }
}
class A{
    int num;
    public A(int num) {
        this.num = num;
    }
}

 

現在就是我們將 實參重新賦值了一個新的對象,那么我們可以發現a指向的對象已經改變,所以當我們對a進行操作時,main函數中的實參就不會改變了。

到這里我們可以總結出:Java中的參數傳遞就是值傳遞,只不過普通類型傳遞的是copy后的值,而對象傳遞的就是地址值,只要你不去改變地址值,那么你在函數中對對象的操作也會影響原來的對象。

那么現在又來了一個問題:

3.Java能不能交換兩個對象呢?

直接上代碼:

package com.cjm.functionparameter;

/**
 * @author 程嘉明
 * @version 創建時間:2018/8/9 12:26
 */
public class ChangeObject {
    public static void main(String[] args) {
        A a1=new A(10);
        A a2=new A(20);
        System.out.println("在執行函數前:a1的值為:"+a1.num+"a2的值為:"+a2.num);
        change(a1,a2);
        System.out.println("在執行函數后:a1的值為:"+a1.num+"a2的值為:"+a2.num);
    }
    public static void change(A a1,A a2){
        A temp=a1;
        a1=a2;
        a2=temp;
    }
}

然而並沒有交換。。。。。。

 我們輸出所有的哈希碼:

package com.cjm.functionparameter;

/**
 * @author 程嘉明
 * @version 創建時間:2018/8/9 12:26
 */
public class ChangeObject {
    public static void main(String[] args) {
        A a1=new A(10);
        A a2=new A(20);
        System.out.println("在執行函數前:a1的值為:"+a1.num+"a2的值為:"+a2.num);
        System.out.println("main函數中的a1的哈希碼為:"+a1.hashCode()+"a2的哈希碼為:"+a2.hashCode());
        System.out.println("############執行函數#############");
        System.out.println();
        change(a1,a2);
        System.out.println("在執行函數后:a1的值為:"+a1.num+"a2的值為:"+a2.num);
        System.out.println("############函數之后#############");
    }
    public static void change(A a1,A a2){
        System.out.println("函數剛開始時的a1的哈希碼為:"+a1.hashCode()+"a2的哈希碼為:"+a2.hashCode());
        A temp=a1;
        a1=a2;
        a2=temp;
        System.out.println("函數中的a1的哈希碼為:"+a1.hashCode()+"a2的哈希碼為:"+a2.hashCode());
    }
}

 

 

 似乎沒有問題:因為在函數中a1和a2的地址值是改變了,但是這是一個地址值,你修改了他有什么作用呢?

 圖解如下:

開始時:

在函數中進行交換:

那么此時main函數中的對象會交換嗎?當然不會!所以還是那一句話:

到這里我們可以總結出:Java中的參數傳遞就是值傳遞,只不過普通類型傳遞的是copy后的值,而對象傳遞的就是地址值,只要你不去改變地址值,那么你在函數中對對象的操作也會影響原來的對象。

 

4.針對一個特殊類String類

為什么說這個String特殊呢?

因為:面試題里面都是拿他做例子所以他特殊(#手動滑稽)

當然不是了,主要是因為String是final類不能在對象上去修改,只能new一個新的對象。

所以看看下面的代碼你就知道我的意思了:

當你的參數拼接后其實已經改變了你這個對象的引用。而你的形參的類型是final的這也就代表着你不能改變他的引用對像。

講這個似乎對我們這個沒有幫助,那么我們來看看下面的代碼:

package com.cjm.functionparameter;

/**
 * @author 程嘉明
 * @version 創建時間:2018/8/9 14:08
 * String類型是否能夠在拼接符的作用下不改變對象
 */
public class StringAdd {
    public static void main(String[] args) {
       String str="101010";
        System.out.println("在沒有進入函數之前String的對象的哈希碼為:"+str.hashCode());
       stringChange(str);
        System.out.println("str經過函數的值為:");
        System.out.println(str);
    }
    public static void stringChange(String str){
        System.out.println("進入函數后沒有修改String之前的Str的哈希碼為:"+str.hashCode());
        str+="aaaa";
        System.out.println("進入函數后修改String之后的Str的哈希碼為:"+str.hashCode());
    }
}

在修改時我們的值沒有發生改變。

就是拼接后你的String對象已經改變,接下來你所做的就與main函數里的str變量沒有關系了。

 

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM