java参数传递的最终理解

来源:互联网 发布:东方不败网络歌手 编辑:程序博客网 时间:2024/05/29 05:54

 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、当传递参数为基本数据类型时,不会对原数据造成任何影响。

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



0 0
原创粉丝点击