java参数传递的最终理解


 java的参数传递一直是个令初学者搞不懂的知识(- - 比如我)。今天决下心来敲代码,研究透彻java的参数传递。

 根据所学习的资料,java的参数传递只有一种——值传递。

可能大部分CS专业的学生(再次——比如我)最初都是由接触C/C++开始,因此印象中总会有两种参数传递类型——1.值传递,2.引用传递。

再说说两种传递类型(浅谈C/C++):

        1.值传递——值传递时内存会将原来的数据拷贝一份,将拷贝的作为参数进行传递,因此在其他地方对该参数所做的修改并不会影响原来的数据。

        2.引用传递——引用传递是将原来数据的地址(java中为引用)直接作为参数进行传递,因此在其他地方对该参数所做的修改相当于修改原数据。

说到这里,就要说说java的特点了——引用,java与C++不同,无指针,java的数据类型分为两种,基本类型和引用类型。但从设计思想的本质看是一样的,都是point的感觉。

java的这个特性很容易使初学者认为java的参数传递就是“引用传递",但其实不是。

           举个例子,

<span style="font-size:14px;">     Exp exp = new Exp();</span>
         new Exp()实例化一个对象,而exp = new Exp();就让exp引用向这个对象,exp在内存开辟的栈中储存实例化对象的地址。当将exp进行参数传递时,值传递的机制在内存栈区创建了一个栈帧,储存的是exp这个引用的拷贝引用,因此传递后刚才的对象变成了两个引用,在栈中,exp和拷贝值储存相同的地址。


下面我直接就以代码来展开吧~

public class TestCall {

<span style="font-size:14px;">    //类成员-------------------------------</span><pre name="code" class="java"><span style="font-size:14px;">    Book bb = new Book("数据结构", 20);
    Book aa = new Book("操作系统", 40);
    Book cc = new Book("改变后1", 20);
    Book dd = new Book("改变后2", 40);
    Book[] book={aa,bb};
    Book[] book1 ={cc,dd};</span>
 
<span style="font-size:14px;">     //内部类------------------------------
	public class Book{
		 private String name;  
		 private double price;  
		  
		 public Book(String name, double price) {  
		    this.name = name;  
		    this.price = price;  
		 }  
		  
		 public void setPrice(double p) {  
		    this.price = p;  
		 }  
	 //覆盖-------------------------------
	  @Override  
      public String toString() {  
         return "[name=" + this.name + ", price=" + this.price + "]";  
	   }  
	}
   //更改对象内容------------------------------
    void adjustPrice(Book aBook) {  
        //aBook.setPrice(100.0);  //---改变了---
    	aBook = new Book("我改了书名",30);//---不改变---
    }  
    void changePrice(Book[] book){
    	//book[1] = new Book("这次是数组,我改了书名",30);//---改变了---
    	book[1].setPrice(100.0);//---改变了---
        //book = book1;//---不变---
        //book[1] = book1[1];//---改变---
        }
    
   //更改基本类型内容------------------------------
    void adjustBase(int a){
    	a = 3;
    }
    void changeBase(int[] a){
    	a[1] = 3;
    }	
}</span>

 这里我将main方法抽取出来便于编写。

 (1)

<span style="font-size:14px;">    public static void main(String[] args){
		TestCall t = new TestCall();
		//对象------具体数组元素做参数---------------------
		System.out.println("前: "+t.book[1]);
		t.adjustPrice(t.book[1]);//具体数组元素做参数
		System.out.println("后: "+t.book[1]);
		System.out.println("");
}</span>

运行结果:

 前: [name=数据结构, price=20.0]
后: [name=数据结构, price=20.0]


结论:可以看到,原数据没有收到影响。

(2)

<span style="font-size:14px;">//对象------直接用对象做参数
System.out.println("前: "+t.bb);
t.adjustPrice(t.bb);
System.out.println("后: "+t.bb);
System.out.println("");</span>

运行结果:

前: [name=数据结构, price=20.0]
后: [name=数据结构, price=20.0]

用图解释下:



结论:原数据没有收到影响。

(3)

<span style="font-size:14px;">//对象数组--------------------------
System.out.println("前: "+t.book[1]);
t.changePrice(t.book);//整个数组的引用做参数
System.out.println("后: "+t.book[1]);
System.out.println("");</span>


运行结果:

前: [name=数据结构, price=20.0]
后: [name=数据结构, price=100.0]

结论: 将数组作为参数传递时,发生了改变。

理解: 数组对象实际上也是引用,值传递后内存栈出现两个引用向实例化数组的对象,但book[i]会操作到原对象进而改变原数据。

再加深理解, 若将类成员方法changePrice(Book[])的方法体改为book = book1;

运行结果是:

前: [name=数据结构, price=20.0]
后: [name=数据结构, price=20.0]

可以看到,这次原数据没有发生改变,为什么呢? 其实就是我们将book引用向了另一个数组book1,操纵的不是源对象,因此原数据没有发生改变。

来到这里

让我们将(2)中的adjustPrice方法的方法体改为

aBook.setPrice(100.0); 
再运行看看结果:

前: [name=数据结构, price=20.0]
后: [name=数据结构, price=100.0]

结论: 我们惊奇地发现,原来的数据居然变了,其实道理也就和上面一样——因为我们操纵了源对象。

         bb对象和值传递时的拷贝值都引用向原来的实例,但aBook.setPrice操纵了源对象,即它们共同引用的对象,因此原数据改变了

用图片来解释下:



(4)

//基本类型-------------------------
int a=1;
System.out.println("a是: "+a);
t.adjustBase(a);
System.out.println("a是: "+a);
System.out.println("");

运行结果:

a是: 1
a是: 1


结论:与单个具体对象一样,不会影响原数据


(5)

//基本类型数组-------------------------
int[] aa={1,2,3,4};
System.out.println("aa[1]是: "+aa[1]);
t.changeBase(aa);
System.out.println("aa[1]是: "+aa[1]);


运行结果:

aa[1]是: 2
aa[1]是: 3


结论:原来数组的值发生了改变,原理如(3)


总结一下:1、本质上,当传递参数为对象时,只要对参数的操作不是对原对象的操作就不会改变原数据的值。

                2、当传递参数为基本数据类型时,不会对原数据造成任何影响。

                     但这里需要强调的是: 若传递的是数组对象(无论是基本类型数据还是对象)而不是具体的单个数组元素,则对传递数据的操作相当于对原数据的操作,即会改变原数据。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值