1. 程式人生 > >關於Java的引用和函式引數傳遞

關於Java的引用和函式引數傳遞

Java中沒有了指標,這有時給程式設計師帶來了些許不便。Java的語言設計者強調,這種不便可以通過Java的引用特性得到彌補。即對於Java的任何物件,我們可以申明物件變數,但不產生例項,這樣,把該變數指向具有實際例項的物件,即可實現同一例項物件的多個變數引用,如:

int x[]={1,2,3,4,5}, y[];

y=x;

for(int i=0; i<y.length; i++) System.out.print(“ ”+y[i]);

則完成了通過yx的引用。從這個實際效果看,y在這裡就很象C語言中的指標了。只不過對於“指標”y我們不能進行+-這類算數運算,即Java的引用只能指向程式限定的能夠訪問的現存物件,所以

Java的實現者認為它是靈活同時也是安全的。

但對於C或者C++中能夠通過函式簡單實現的兩個數交換問題,即C++如下函式:

void swap(int &x, int &y) { int t; t=x; x=y; y=t; }

Java中是否能夠實現呢?

按照Java的規定,Java的函式引數在傳遞的時候有兩種方式。對於基本型別,如intdouble等作為函式引數傳遞時,採取的是傳值方式。而對於物件,如陣列、字串等作為引數傳遞時,採用的是引用方式,即此時在函式中對傳遞的物件的修改將完全影響原物件。那能否對於物件利用引用完成值的交換呢?下面的程式充分地演示了這個問題:

public class test {

public static void main(String[] arg) {

int x1[]={1,2,3},x2[]={3,2,1};

swap(x1,x2);//採用swap函式,即直接利用引數引用進行交換

System.out.print("swap->X1:/t"); printarr(x1);

System.out.print("swap->X2:/t"); printarr(x2);

swapArray(x1,x2);//採用swapArray函式,利用對於物件的值的修改進行交換

System.out.print("swapArr->X1:/t"); printarr(x1);

System.out.print("swapArr->X2:/t"); printarr(x2);

Object t;

t=x1; x1=x2; x2=(int[])t;//在非函式呼叫中直接利用引用進行交換

System.out.print("Tswap->X1:/t"); printarr(x1);

System.out.print("Tswap->X2:/t"); printarr(x2);

}

public static void swap(Object x, Object y) {//直接利用引數引用交換

Object t=x;

x=y;

y=t;

}

public static void swapArray(int x[], int y[]) {//對引用物件的值進行修改完成交換

if(x.length!=y.length) return;

int t[]=x.clone();

for(int i=0; i<x.length; i++) x[i]=y[i];

for(int i=0; i<y.length; i++) y[i]=t[i];

}

public static void printarr(int x[]) {//列印陣列

for(int i=0; i<x.length; i++) System.out.print(x[i]+"");

System.out.println();

}

}

在函式swap中,我們直接利用引數進行交換。在函式swapArray中,我們通過修改引數指向的兩個陣列的值進行交換。而在main函式沒有進行函式引數傳遞的情況下,我們直接利用引數的引用進行了一次交換。

程式的執行結果如下:

swap->X1:123

swap->X2:321

swapArr->X1:321

swapArr->X2:123

Tswap->X1:123

Tswap->X2:321

從執行結果我們可以清楚地看到,函式swap實際沒有完成交換,而函式swapArray和直接在main中利用引用進行的交換是成功的。從這裡我們可以得知,雖然Java的引用可以實現CC++的指標的類似的效果,這在主函式中的引用交換得到了證明。但是一但進行了函式的引數傳遞,這種引用方式的交換便實效了。雖然它的交換方式和主函式中利用Object引用t進行的交換方式相同。猜測其原因(因為我不是Java的實現者),只能說明,函式中的引用變數和主函式中呼叫的變數是不相同的。即在呼叫swap函式時,雖然將x1的引用傳遞給了xx2傳遞給了yxy進行了交換,但x1x2並沒有進行交換。也就是說,在函式swap申明引數xy時,實際另外真正的生成了與x1x2完全不相干的引用,只不過xy都同樣指向了x1x2罷了,即此時,陣列物件x1x2同時分別有兩個指標xx1yy1指向它們。這樣的結果當然不能完成如CC++類似的交換。唯一的辦法是如swapArray函式中一樣,不要試圖交換,只能試圖修改引數所指向的兩個物件的值來達到交換的效果。

所以我得出的一個相關的結論是:Java永遠也不能實現如CC++一樣的swap函式。

 

相關推薦

關於Java引用函式引數傳遞

Java中沒有了指標,這有時給程式設計師帶來了些許不便。Java的語言設計者強調,這種不便可以通過Java的引用特性得到彌補。即對於Java的任何物件,我們可以申明物件變數,但不產生例項,這樣,把該變數指向具有實際例項的物件,即可實現同一例項物件的多個變數引用,如: int

js中的型別函式引數傳遞型別問題

js中的型別: 2大型別:原始型別和物件。 原始型別有 boolean、number、string這三個普通原始型別,還有null、undefined這倆特殊原始型別 物件嘛就多了,普通物件、內建物件、全域性物件、函式、陣列等。 函式引數傳遞型別:   對於原始型別,傳遞的是值,

java面向物件(類與物件,區域性變數成員變數,基本型別引用型別作為引數傳遞

一.類和物件的區別 類是對某一類事物的抽象描述,而物件用於表示現實中該類事物的個體 可以將玩具模型看作是一個類,將一個個玩具看作物件,從玩具模型和玩具之間的關係便可以看出類與物件之間的關係。類用於描述多個物件的共同特徵,它是物件的模板。物件用於描述現實中的個體,它是類的例項 二.區域性變數和成員變數

C# 函式引數傳遞(按值引用)

先來說下C#中的資料型別.分值型別和引用型別兩大類.   值型別:直接儲存資料的值,儲存在記憶體中的stack(堆疊)中   引用型別:儲存對值的引用,實際上儲存的就是一個記憶體的地址.引用型別的儲存分成兩塊,實際值儲存在託管堆(heap)中.實際值的記憶體地址儲存在

JS中的函式引數傳遞到底是按值傳遞還是按引用傳遞

首先我們知道JS中的資料型別大致可以分為簡單資料型別和複雜資料型別; 當我們宣告一個變數並給它賦值時,可以賦給其簡單值和複雜值(以下堆記憶體和棧記憶體的地址表示均隨意取的,只是為了區分,不代表真實的記憶體地址); 針對簡單資料型別: 例1 var simpleData1 = 18 v

指標引用 作為函式引數

*和& * * 有兩個作用,一個是作為識別符號來表示這是一個指標(宣告變數時的等號左邊),也就是說存放的是地址,另外一個是作為運算子來取值(賦值等號左邊)。 int *p=NULL; int a = 1; p = &a; cout<<p<<

基本型別引用型別作為引數傳遞(重要)

基本型別和引用型別作為引數傳遞 引用型別資料和基本型別資料作為引數傳遞有沒有差別呢?我們用如下程式碼進行說明,並配合圖解讓大家更加清晰 1.基本資料型別傳遞 基本型別作為引數傳遞時,其實就是將基本型別變數x空間中的值複製了一份傳遞給呼叫的方法show(),當在show()方法中

JAVA基本資料型別、引用資料型別-引數傳遞詳解

1:基本型別的引數傳值 對於基本資料型別,修改這個值並不會影響作為引數傳進來的那個變數,因為你修改的是方法的區域性變數,是一個副本。實參的精度級別應等於或低於形參的精度級別,否則報錯。 class JB{ void f(int x, int y){ x=x+1;

學習筆記-Java基礎 關於函式引數傳遞問題

當引數為基本資料型別時,傳遞方式為值傳遞。 當引數為物件型別時, 傳遞方式為引用傳遞,此引用是複製出來的引用,所以在函式中進行交換引用操作,不會影響到函式外的引用。 雖然引用不是同一個,但是引用對應的物件例項卻是同一個,也就是說可以改變物件例項的成員變數值。 String 和

[10]基本型別引用型別的引數傳遞(圖)

前言:主要為個人筆記 基本型別 程式碼: class Demo{ public static void main(String[] args){ int x=4;

陣列指標做函式引數傳遞

#include<iostream> using namespace std; void callByValue(int arr[], int n) { printf("\ncallByValue:"); for (int i = 0;i < 10;

基本資料型別引用資料型別引數傳遞的不同

程式碼: public class Demo1 { public static void main(String[] args) { int a = 10; int b= 20; System.out.println(a+"___"

Java中方法呼叫引數傳遞的方式是傳值,儘管傳的是引用的值而不是物件的值。(Does Java pass by reference or pass by value?)

原文地址:http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html 在Java中,所有的物件變數都是引用,Java通過引用來管理物件。然而在給方法傳參時,Java並沒有使用傳引用的方式,而是

結構體變數結構體指標變數作為函式引數傳遞的問題

/*2015年8月28日13:20:28通過函式完成對結構體變數的輸入和輸出*/# include <stdio.h># include <string.h>struct Student{int age;char sex;char name[100];

Python學習之函式引數傳遞:傳值 or 引用 ?

在學完Python函式那一章節時,很自然的的就會想到Python中函式傳參時傳值呢?還是傳引用?或者都不是? 我回去看了看我以前做的關於淺拷貝與深拷貝的筆記,其實那裡也已經涉及了一些引用相關的問題了。不過在這裡還是再進行一次總結吧。 在回答上面的問題之前我們先

【轉】C++函式引數傳遞中的一級指標二級指標【【**】】

主要內容: 1、一級指標和二級指標 2、函式指標傳遞的例子 3、什麼時候需要傳遞二級指標? 4、二級指標在連結串列中的使用 1、一級指標和二級指標 一級指標:即我們一般說的指標,就是記憶體地址; 二級指標:指向指標的指標,就是

C++中函式引數傳遞(值傳遞、指標傳遞引用傳遞

今天想寫一個函式,從函式中把我需要的兩個值傳出來,由於傳出來的值比較多,所以不考慮用return來返回,需要通過引數把修改後的值拉出來供我使用,很當然的就想到了用指標,但是值就是傳不出來;使我對原有的大腦中指標的思維產生混沌感,今天一上午才把函式傳遞又走了

shell指令碼引數傳遞main函式引數傳遞方式類似

shell指令碼 test.sh呼叫的時候傳入引數,param1,param2: #test.sh param1 param2 那麼在指令碼內部相當於把 test.sh param1 param2 看成三個引數出入,所以引數0為$0 (test.sh),引數1為$1 (pa

C++函式傳參:引用const引數

一  在函式傳參中使用引用 1.使用例子: #include<iostream> using namespace std; void reset(int &i){//引用傳參

C#值型別引用型別的引數傳遞(ref,out)

C#中有兩種型別,值型別,和引用型別。在記憶體中值型別是直接儲存在記憶體的棧中的,引用型別在棧中存放一個地址,這個地址指向堆中的資料(引用型別的資料是存放在堆中的)下面我們來看看兩種型別引數傳遞有什麼區別先看一個例子 /// <summary>    ///