日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

(重要)java都是值传递,与对象形参所指向的对象改变,其实参所指向的对象也相应改变并不矛盾(2011年9.30日一天写的两个程序的总结结果)...

發布時間:2025/4/14 编程问答 37 豆豆

1.0建立二叉樹的代碼,在java中必須創建二叉樹的方法必須用返回值,因為不存在c語言中的引用傳遞,在java中只有值傳遞 代碼1為正確,代碼2(沒有使用返回值)為錯誤。那么為什么之前的例子中將對象作為參數時,對對象內容的更改還是正確的,也沒有使用返回值,二者看似矛盾,其實并不矛盾,以前都沒有理解到這個本質,本質就是參數中,確實是有一個臨時變量,交換形式對象參數,實際的參數不會改變,但是改變形式參數的引用所指向的內容,即這個對象本身改變,其實參所引用的對象也是同一個對象,當然該對象也會發生變化,因為實參和形參引用的都是同一個對象,只不過是兩份地址的拷貝。

即便是c語言如果不用引用傳遞-&,就是說用指針,也需要用返回值的方法建立二叉樹,才能將已建立好的二叉樹頭指針返回給打印函數的參數。當然java中可以采用對私有變量等操作,即不不使用參數傳遞,而僅僅是創建函數和打印函數共同操作的是同一個變量也可以吧,估計遞歸就不好用了,這個怎么做沒去想!~~~

錯誤代碼:這個時候打印出來的樹的節點為空,printInOrder(tree1)輸出節點為空:

View Code import java.util.*;

class TNode{
int data;
TNode lchild;
TNode rchild;
TNode(int a)
{
data=a;
lchild=null;
rchild=null;
}
}

public class BTree {

static TNode root=new TNode(1);

static void creatTree(TNode root)
{
Scanner in=new Scanner(System.in);
int a=in.nextInt();
if(a==0){
root=null;
return;

}

else{
root=new TNode(a);
creatTree(root.lchild);
creatTree(root.rchild);
}
}
static void printInOrder(TNode root){
if(root==null)
return;
else{

System.out.print(root.data);
printInOrder(root.lchild);
printInOrder(root.rchild);
}

}



public static void main(String[] args) {
// TODO Auto-generated method stub

creatTree(root);
printInOrder(root);




}

}


正確代碼:

View Code import java.util.Scanner;

class Tode{

int data;

Tode lchild;

Tode rchild;

Tode(int a)

{

data=a;

lchild=null;

rchild=null;

}

}

public class TREE{

static Tode root=null;

static Tode creatTree(Tode root)

{

Scanner in=new Scanner(System.in);

int a=in.nextInt();

if(a==0){

return null ;

}

else{

root=new Tode(a);

root.lchild=creatTree(root.lchild);

root.rchild=creatTree(root.rchild);

return root;

}

}

static void printInOrder(Tode root){

if(root==null)

return;

else{

System.out.print(root.data);

printInOrder(root.lchild);

printInOrder(root.rchild);

}

}

public static void main(String[] args) {

// TODO Auto-generated method stub

Tode tree1=creatTree(root);

printInOrder(tree1);

}

}



1.1、疑惑解決了,原來認為方法中傳入一個對象的話(數組也行),如果方法內部對這個對象的內部參數進行了更改,則其實就是對外部的這個靜態對象也進行了修改,相當于c++中的真正的引用傳遞吧,但是傳入的是整型等普通類型,則還是不能夠更改,可以見下面的實例。如果傳入的對象是數組的話,也可以更改,因為java中數組也是對象~,其實也不是 因為是對引用所指向的內容進行了修改,引用可以有多個,但是引用所指向的內容只有一份!!!!!!

以下程序的輸出結果是0? 1? 2

View Code import java.util.*;

class node{
int data;
node lchild;
node rchild;
public node(int a){
data=a;
lchild=null;
rchild=null;
}
}

public class testclass2 {

public void changeroot(node root){
node newnode1=new node(1);
node newnode2=new node(2);
root.lchild=newnode1;
root.rchild=newnode2;
}

public void print(node root){

System.out.println(root.data);
System.out.print(root.lchild.data);
System.out.print(root.rchild.data);

}
public static void main(String[] args){
node root=new node(0);
testclass2 dd=new testclass2();
dd.changeroot(root);
dd.print(root);

}

}



1.2、下面是另一個例子,在算法例子中也常用到因為是 對引用所指向的內容進行了修改,引用可以有多個,但是引用所指向的內容只有一份!!!!!!

以下程序輸出結果是2 4 3 4

View Code void diguiInorderTraverse(node root){
root.lchild
}
解釋說的通了,傳入root,對root修改,其實就相當于


class A{
int b=2;
}
public class Testclass {
static A a=new A();
static void changeA(A a){
a.b=3;
}
static int b=4;
static void changeB(int b){
b=5;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(a.b);
System.out.println(b);
changeA(a);
changeB(b);
System.out.println(a.b);
System.out.println(b);

}
}

1.3、也就是說root對象確實分配了一個臨時對象,傳入的都是地址的引用,所以對這個參數的改變,對引用所指向的內容進行了修改,引用可以有多個,但是引用所指向的內容只有一份!!!!!!

?我看了一些引用調用和值調用的定義,很多人都把是傳遞值,還是傳遞地址?是改變參數自身內容,還是改變參數所指向的地址中的內容作為區別這兩種調用的標志。這很不恰當,這些說法很容易讓我們聯想到Java的對象參數傳遞是引用調用,實際上,Java的對象傳遞仍然是值調用。

???? ? ?引用調用:在參數傳遞的過程中,形參并不是實參的副本,而是實參本身。這種調用實參和形參在內存中實際上都是同樣的一個區域,只是這個區域的表示(參數名)不同而已。

???

???? ? ?值調用:在參數傳遞過程中,創建了一個實參的副本——形參。形參和實參在內存中是兩個完全不同的區域。因此形參內容的改變并不能影響到實參。

???方法調用(call by)?是一個標準的計算機科學術語。方法調用根據參數傳遞的情況又分為值調用(?call by reference?)?引用調用(?call by value?)?。江湖上有很多關于這兩種調用的定義 ,最通常的說法是傳遞值的是值調用,傳遞地址的是引用調用。這其實很不恰當,這種?這些說法很容易讓我們聯想到Java的對象參數傳遞是引用調用,實際上,Java的對象參數傳遞仍然是值調用??

?

以下摘自該段落:

http://hxraid.iteye.com/blog/428856

?????
我們首先用一段代碼來證實一下為什么Java的對象參數傳遞?是值調用。

Java代碼??

1.?? public?class?Employee?{??

2.?? ??

3.?? ????public?String?name=null;??

4.?? ??????

5.?? ????public?Employee(String?n){??

6.?? ????????this.name=n;??

7.?? ????}??

8.?? ????//將兩個Employee對象交換??

9.?? ????public?static?void?swap(Employee?e1,Employee?e2){??

10.? ????????Employee?temp=e1;??

11.? ????????e1=e2;??

12.? ????????e2=temp;??

13.? ????????????????System.out.println(e1.name+"?"+e2.name);?//打印結果:李四?張三??

14.? ????}??

15.? ????//主函數??

16.? ????public?static?void?main(String[]?args)?{??

17.? ????????Employee?worker=new?Employee("張三");??

18.? ????????Employee?manager=new?Employee("李四");??

19.? ????????swap(worker,manager);??

20.? ????????System.out.println(worker.name+"?"+manager.name);?//打印結果仍然是:?張三?李四??

21.? ????}??

22.? }??

?

????? 上面的結果讓人很失望,雖然形參對象e1,e2的內容交換了,但實參對象worker,manager并沒有互換內容。這里面最重要的原因就在于形參e1,e2是實參worker,manager的地址拷貝。

????? 大家都知道,在Java中對象變量名實際上代表的是對象在堆中的地址(專業術語叫做對象引用?)。在Java方法調用的時候,參數傳遞的是對象的引用。重要的是,形參和實參所占的內存地址并不一樣,形參中的內容只是實參中存儲的對象引用的一份拷貝。

???? ??如果大家對JVM內存管理中Java?局部變量區?有所了解的話(可以參見《?Java 虛擬機體系結構?),就很好理解上面這句話。在JVM運行上面的程序時,運行main方法和swap方法,會在Java棧中先后push兩個叫做棧幀?的內存空間。main棧幀中有一塊叫局部變量區的內存用來存儲實參對象workermanager的引用。而swap棧幀中的局部變量區則存儲了形參對象e1e2的引用。雖然e1e2的引用值分別與workermanager相同,但是它們占用了不同的內存空間。當e1e2的引用發生交換時,下面的圖很清晰的看出完全不會影響workermanager的引用值。

?????????????

????? Java對象參數傳遞雖然傳遞的是地址(引用),但仍然是值調用。是時候需要給引用調用和值調用一個準確的定義了。

?

??????值調用(call by value)??在參數傳遞過程中,形參和實參占用了兩個完全不同的內存空間。形參所存儲的內容是實參存儲內容的一份拷貝。實際上,Java對象的傳遞就符合這個定義,只不過形參和實參所儲存的內容并不是常規意義上的變量值,而是變量的地址。咳,回過頭想想:變量的地址不也是一種值嗎!

??????引用調用(call by reference)??在參數傳遞的過程中,形參和實參完全是同一塊內存空間,兩者不分彼此。?實際上,形參名和實參名只是編程中的不同符號,在程序運行過程中,內存中存儲的空間才是最重要的。不同的變量名并不能說明占用的內存存儲空間不同。

?

????? 大體上說,兩種調用的根本并不在于傳遞的是值還是地址(畢竟地址也是一個值),而是在于形參和實參是否占用同一塊內存空間。事實上,C/C++的指針參數傳遞也是值調用,不信試試下面的C代碼吧!

C代碼??

1.? #include<stdio.h>??

2.? void?swap(int?*a1,int?*b1){??

3.? ????int?*t=a1;??

4.? ????a1=b1;??

5.? ????b1=t;??

6.? }??

7.? int?main(){??

8.? ????int?x1=100;??

9.? ????int?x2=200;??

10. ????????int?*a=&x1;??

11. ????int?*b=&x2;??

12. ????printf("%d?%d\n",*a,*b);??

13. ????swap(a,b);??

14. ????printf("%d?%d\n",*a,*b);??

15. ????return?0;??

16. }??

???????? C/C++是有引用調用的,這就是C/C++一種叫做引用的變量聲明方法: int a; int &ra=a; 其中raa的別名,兩者在內存中沒有區別,占用了同一個內存空間。而通過引用(別名)的參數傳遞就符合引用調用的特點了。大家可以去試試

void swap(int &a1,int &b1);的運行結果。

?

轉載于:https://www.cnblogs.com/wangzhewang/archive/2011/09/30/2196744.html

總結

以上是生活随笔為你收集整理的(重要)java都是值传递,与对象形参所指向的对象改变,其实参所指向的对象也相应改变并不矛盾(2011年9.30日一天写的两个程序的总结结果)...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。