Java中沒有指針,所以也沒有引用傳遞了,僅僅有值傳遞
不過可以通過對象的方式來實現引用傳遞 類似java沒有多繼承 但可以用多次implements
接口實現多繼承的功能
值傳遞:方法調用時,實際參數把它的值傳遞給對應的形式參數,方法執行中形式參數值的改變不影響實際參
引用傳遞:也稱爲傳地址。方法調用時,實際參數的引用(地址,而不是參數的值)被傳遞給方法中相對應的形式參數,在方法執行中,對形式參數的操作實際上就是對實際參數的操作,方法執行中形式參數值的改變將會影響實際參數的值。
Java參數按值傳遞
面試題:當一個對象被當作參數傳遞到一個方法後,此方法可改變這個對象的屬性,並可返回變化後的結果,那麼這裏到底是值傳遞還是引用傳遞?
答:是值傳遞。Java
編程語言只有值傳遞參數。當一個對象實例作爲一個參數被傳遞到方法中時,參數的值就是該對象的引用一個副本。指向同一個對象,對象的內容可以在被調用的方法中改變,但對象的引用(不是引用的副本)是永遠不會改變的。
-------------------------------------------------------------
在 Java
應用程序中永遠不會傳遞對象,而只傳遞對象引用。因此是按引用傳遞對象。但重要的是要區分參數是如何傳遞的,這纔是該節選的意圖。Java
應用程序按引用傳遞對象這一事實並不意味着 Java 應用程序按引用傳遞參數。參數可以是對象引用,而 Java
應用程序是按值傳遞對象引用的。
Java
應用程序中的變量可以爲以下兩種類型之一:引用類型或基本類型。當作爲參數傳遞給一個方法時,處理這兩種類型的方式是相同的。兩種類型都是按值傳遞的;沒有一種按引用傳遞。
按
值傳遞意味着當將一個參數傳遞給一個函數時,函數接收的是原始值的一個副本。因此,如果函數修改了該參數,僅改變副本,而原始值保持不變。按引用傳遞意味
着當將一個參數傳遞給一個函數時,函數接收的是原始值的內存地址,而不是值的副本。因此,如果函數修改了該參數的值,調用代碼中的原始值也隨之改變。如果
函數修改了該參數的地址,調用代碼中的原始值不會改變.
當傳遞給函數的參數不是引用時,傳遞的都是該值的一個副本(按值傳遞)。區別在於引用。在 C++
中當傳遞給函數的參數是引用時,您傳遞的就是這個引用,或者內存地址(按引用傳遞)。在 Java
應用程序中,當對象引用是傳遞給方法的一個參數時,您傳遞的是該引用的一個副本(按值傳遞),而不是引用本身。
Java 應用程序按值傳遞參數(引用類型或基本類型),其實都是傳遞他們的一份拷貝.而不是數據本身.(不是像 C++
中那樣對原始值進行操作。)
例1:
- //在函數中傳遞基本數據類型,
- public class Test {
- public static void change( int i, int j) {
- int temp = i;
- i = j;
- j = temp;
- }
- public static void main(String[] args) {
- int a = 3 ;
- int b = 4 ;
- change(a, b);
- System.out.println( "a=" + a);
- System.out.println( "b=" + b);
- }
- }
- 結果爲:
- a= 3
- b= 4
- 原因就是 參數中傳遞的是 基本類型 a 和 b 的拷貝,在函數中交換的也是那份拷貝的值 而不是數據本身;
例2:
- //傳的是引用數據類型
- public class Test {
- public static void change( int [] counts) {
- counts[ 0 ] = 6 ;
- System.out.println(counts[ 0 ]);
- }
- public static void main(String[] args) {
- int [] count = { 1 , 2 , 3 , 4 , 5 };
- change(count);
- }
- }
- 在方法中 傳遞引用數據類型 int 數組,實際上傳遞的是其引用count的拷貝,他們都指向數組對象,在方法中可以改變數組對象的內容。即:對複製的引用所調用的方法更改的是同一個對象。
例3:
- //對象的引用(不是引用的副本)是永遠不會改變的
- class A {
- int i = 0 ;
- }
- public class Test {
- public static void add(A a) {
- a = new A();
- a.i++;
- }
- public static void main(String args[]) {
- A a = new A();
- add(a);
- System.out.println(a.i);
- }
- }
- 輸出結果是 0
- 在該程序中,對象的引用指向的是A ,而在change方法中,傳遞的引用的一份副本則指向了一個新的OBJECT,並對其進行操作。
- 而原來的A對象並沒有發生任何變化。 引用指向的是還是原來的A對象。
例4:
String 不改變,數組改變
- public class Example {
- String str = new String( "good" );
- char [] ch = { 'a' , 'b' , 'c' };
- public static void main(String args[]) {
- Example ex = new Example();
- ex.change(ex.str, ex.ch);
- System.out.print(ex.str + " and " );
- System.out.println(ex.ch);
- }
- public void change(String str, char ch[]) {
- str = "test ok" ;
- ch[ 0 ] = 'g' ;
- }
- }
- 程序 3 輸出的是 good and gbc.
- String 比較特別,看過String 代碼的都知道, String 是 final 的。所以值是不變的。 函數中String對象引用的副本指向了另外一個新String對象,而數組對象引用的副本沒有改變,而是改變對象中數據的內容.
- 對於對象類型,也就是Object的子類,如果你在方法中修改了它的成員的值,那個修改是生效的,方法調用結束後,它的成員是新的值,但是如果你把它指向一個其它的對象,方法調用結束後,原來對它的引用並沒用指向新的對象。
下面舉例說明:
- class Test
- {
- public static void main(String args[])
- {
- int val;
- StringBuffer sb1, sb2;
- val = 10;
- sb1 = new StringBuffer ("apples" );
- sb2 = new StringBuffer ("pears" );
- System .out.println("val is " + val);
- System .out.println("sb1 is " + sb1);
- System .out.println("sb2 is " + sb2);
- System .out.println("" );
- System .out.println("calling modify" );
- // 按值傳遞所有參數
- modify(val, sb1, sb2);
- System .out.println("returned from modify" );
- System .out.println("" );
- System .out.println("val is " + val);
- System .out.println("sb1 is " + sb1);
- System .out.println("sb2 is " + sb2);
- }
- public static void modify(int a, StringBuffer r1,
- StringBuffer r2)
- {
- System .out.println("in modify..." );
- a = 0;
- r1 = null ; //1
- r2.append(" taste good" );
- System .out.println("a is " + a);
- System .out.println("r1 is " + r1);
- System .out.println("r2 is " + r2);
- }
- }
- val is 10
- sb1 is apples
- sb2 is pears
- calling modify
- in modify...
- a is 0
- r1 is null
- r2 is pears taste good
- returned from modify
- val is 10
- sb1 is apples
- sb2 is pears taste good
這段代碼聲明瞭三個變量:一個整型變量和兩個對象引用。設置了每個變量的初始值並將它們打印出來。然後將所有三個變量作爲參數傳遞給 modify 方法。
modify 方法更改了所有三個參數的值:
將第一個參數(整數)設置爲 0 。
將第一個對象引用 r1 設置爲 null 。
保留第二個引用 r2 的值,但通過調用 append 方法更改它所引用的對象(這與前面的 C++ 示例中對指針 p 的處理類似)。
當執行返回到 main 時,再次打印出這三個參數的值。正如預期的那樣,整型的 val 沒有改變。對象引用 sb1 也沒有改變。如果 sb1 是按引用傳遞的,正如許多人聲稱的那樣,它將爲 null 。但是,因爲 Java 編程語言按值傳遞所有參數,所以是將 sb1 的引用的一個副本傳遞給了 modify 方法。當 modify 方法在 //1 位置將 r1 設置爲 null 時,它只是對 sb1 的引用的一個副本進行了該操作,而不是像 C++ 中那樣對原始值進行操作。
另外請注意,第二個對象引用 sb2 打印出的是在 modify 方法中設置的新字符串。即使 modify 中的變量 r2 只是引用 sb2 的一個副本,但它們指向同一個對象。因此,對複製的引用所調用的方法更改的是同一個對象。
public class PassValue{
static void exchange(int a, int b){//靜態方法,交換a,b的值
int temp;
temp = a;
a = b;
b = temp;
}
public static void main(String[] args){
int i = 10;
int j = 100;
System.out.println("before call: " + "i=" + i + "/t" + "j = " + j);//調用前
exchange(i, j); //值傳遞,main方法只能調用靜態方法
System.out.println("after call: " + "i=" + i + "/t" + "j = " + j);//調用後
}
}
運行結果:
before call: i = 10 j = 100
after call: i = 10 j = 100
說明:調用exchange(i, j)時,實際參數i,j分別把值傳遞給相應的形式參數a,b,在執行方法exchange()時,形式參數a,b的值的改變不影響實際參數i和j的值,i和j的值在調用前後並沒改變。
引用傳遞---對象作爲參數
如果在方法中把對象(或數組)作爲參數,方法調用時,參數傳遞的是對象的引用(地址),即在方法調用時,實際參數把對對象的 引用(地址)傳遞給形式參數。這是實際參數與形式參數指向同一個地址,即同一個對象(數組),方法執行時,對形式參數的改變實際上就是對實際參數的改變, 這個結果在調用結束後被保留了下來。
class Book{
String name;
private folat price;
Book(String n, float ){ //構造方法
name = n;
price = p;
}
static void change(Book a_book, String n, float p){ //靜態方法,對象作爲參數
a_book.name = n;
a_book.price = p;
}
public void output(){ //實例方法,輸出對象信息
System.out.println("name: " + name + "/t" + "price: " + price);
}
}
public class PassAddr{
public static void main(String [] args){
Book b = new Book("java2", 32.5f);
System.out.print("before call:/t"); //調用前
b.output();
b.change(b, "c++", 45.5f); //引用傳遞,傳遞對象b的引用,修改對象b的值
System.out.print("after call:/t"); //調用後
b.output();
}
}
運行結果:
before call: name:java2 price:32.5
after call: name:c++ price:45.5
說明:調用change(b,"c++",45.5f)時,對象b作爲實際參數,把引用傳遞給相應的形式參數a_book,實際上a_book也指向同一 個對象,即該對象有兩個引用名:b和a_book。在執行方法change()時,對形式參數a_book操作就是對實際參數b的操作。