public class CallValueOrAddress{ private String name; private int age; public void setName(String name){ this.name=name; } public String getName(){ return name; } public void setAge(int age){ this.age=age; } public int getAge(){ return age; } public static void main(String agrs[]){ String str_name="wangxianxing"; String new_name="nihao"; int int_age=21; int new_age=22; System.out.println("傳值引用"); System.out.println("姓名:"+str_name+"年齡:"+int_age); new_name=str_name; new_name=new String("nihaoma?"); new_age=int_age; new_age=22; System.out.println("姓名:"+str_name+"年齡:"+int_age); CallValueOrAddress cvoa=new CallValueOrAddress(); cvoa.setName("wangxianxing"); cvoa.setAge(21); System.out.println("傳址引用"); System.out.println("姓名:"+cvoa.getName()+"年齡:"+cvoa.getAge()); CallValueOrAddress new_cvoa=cvoa; new_cvoa.setName("kingxianstar"); new_cvoa.setAge(22); System.out.println("姓名:"+cvoa.getName()+"年齡:"+cvoa.getAge()); System.out.println("例外情況一"); new_cvoa=new CallValueOrAddress(); new_cvoa.setName("kingxianstar+kingxianstar"); new_cvoa.setAge(32); System.out.println("姓名:"+cvoa.getName()+"年齡:"+cvoa.getAge()); } }
運行結果如下:
傳值引用
姓名:wangxianxing年齡:21
姓名:wangxianxing年齡:21
傳址引用
姓名:wangxianxing年齡:21
姓名:kingxianstar年齡:22
例外情況一
姓名:kingxianstar年齡:22
感覺還不是很全面,所以在網上又搜索了一下,發現了這篇(http://mgc.name/article.asp?id=842)
class Foo { private int x; public Foo(int x) { this.x = x; } public void setX(int x) { this.x = x; } public int getX() { return x; } } public class Submit { static Foo fooBar(Foo foo) { foo = new Foo(100); return foo; } public static void main(String[] args) { Foo foo = new Foo(300); System.out.print(foo.getX() + "-"); Foo fooFoo = fooBar(foo); System.out.print(foo.getX() + "-"); System.out.print(fooFoo.getX() + "-"); foo = fooBar(fooFoo); System.out.print(foo.getX() + "-"); System.out.print(fooFoo.getX()); } }
What is the output of the program shown in the exhibit?
A. 300-100-100-100-100
B. 300-300-100-100-100
C. 300-300-300-100-100
D. 300-300-300-300-100
Answer: B
涉及知識點:
1.Java中的參數傳遞有傳值和傳址兩種;
2.基本類型和String型作為參數時,為傳值方式,只把值傳入方法,不管在方法中怎么處理這個參數,原值不變;
3.其他引用類型作為參數時,為傳址方式,將指向內存中的地址傳入方法,方法中此內存地址中的值發生變化時,原值也會改變;
4.例外:
(1)如果引用類型的對象通過傳址方式將其指向內存中的地址傳入方法后,方法中使用new關鍵字重新給參數賦值時,會在內存中重新開辟空間,參數指向新的內存空間,此時參數和原對象指向的就不是同一個地址了,參數值的變化不會改變原值;
(2)String型是引用類型,但是String型作為參數,是傳值方式,可以通過以下兩種方式來理解:
<1>String本質上是基本類型的char[],基本類型作為參數時,為傳值方式;
<2> 字符串在內存中是存儲在堆中的一個常量,String對象指向內存中這個常量的地址,通過傳址方式將地址傳入方法后,方法中如果通過字符串給參數賦值,則會重新在堆中創建一個字符串常量,並指向這個地址,原值依然指向原來的字符串常量地址,參數值的變化不會改變原值,如果通過new關鍵字給參數賦值,參見 (1)中的解釋。
解析:
1.“Foo foo = new Foo(300);”,此時foo.getX()的值為300;
2.“Foo fooFoo = fooBar(foo);”,因為Foo是引用類型,main方法中的foo通過傳址的方式將其指向的地址傳給fooBar方法中的foo,此時兩個foo指向同一個地址,foo.getX()的值都為300;通過“new Foo(100)”給fooBar方法中的foo賦值后,該foo重新指向了一個新的地址,foo.getX()的值為新地址中的值100,而main方法中的foo仍然指向原來的地址,foo.getX()的值沒有改變,仍為 300;fooBar將foo的值返回給fooFoo,因此fooFoo.getX()的值為100;
3.“foo = fooBar(fooFoo);”,同2中的解釋,foo.getX()的值變為100,fooFoo.getX()的值沒有變化,仍為100;