(重要)java都是值传递,与对象形参所指向的对象改变,其实参所指向的对象也相应改变并不矛盾(2011年9.30日一天写的两个程序的总结结果)...
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棧幀中有一塊叫局部變量區的內存用來存儲實參對象worker和manager的引用。而swap棧幀中的局部變量區則存儲了形參對象e1和e2的引用。雖然e1和e2的引用值分別與worker和manager相同,但是它們占用了不同的內存空間。當e1和e2的引用發生交換時,下面的圖很清晰的看出完全不會影響worker和manager的引用值。
?????????????
????? 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; 其中ra是a的別名,兩者在內存中沒有區別,占用了同一個內存空間。而通過引用(別名)的參數傳遞就符合引用調用的特點了。大家可以去試試
void swap(int &a1,int &b1);的運行結果。
?
轉載于:https://www.cnblogs.com/wangzhewang/archive/2011/09/30/2196744.html
總結
以上是生活随笔為你收集整理的(重要)java都是值传递,与对象形参所指向的对象改变,其实参所指向的对象也相应改变并不矛盾(2011年9.30日一天写的两个程序的总结结果)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [转]SQL,LINQ,Lambda语法
- 下一篇: 雪碧图(精灵图)