收藏 分享(赏)

Java值传递和引用.doc

上传人:fmgc7290 文档编号:7117914 上传时间:2019-05-06 格式:DOC 页数:6 大小:38.50KB
下载 相关 举报
Java值传递和引用.doc_第1页
第1页 / 共6页
Java值传递和引用.doc_第2页
第2页 / 共6页
Java值传递和引用.doc_第3页
第3页 / 共6页
Java值传递和引用.doc_第4页
第4页 / 共6页
Java值传递和引用.doc_第5页
第5页 / 共6页
点击查看更多>>
资源描述

1、1java语言深入( java中是传值还是引用)关键字 : java基础深入 熟悉 C 的程序员都用过指针,对指针可谓爱之深恨之切。指针是指向一块内存地址的内存数据(有些拗口),也就是说指针本身是一个占用 4 字节内存的 int( 32 位系统内),而这个 int值恰恰又是另一块内存的地址。比如 “hello“这个字串,存放在0x0000F000这个地址到 0x0000F005这段内存区域内(包括 0x00的结束字节)。而在 0x0000FFF0到 0x0000FFF03这四个字节内存放着一个 int,这个 int的值是 0x0000F000。这样就形成了一个指向 “hello“字串的指针。

2、在 Java中,很多人说没有指针,事实上,在 Java更深层次里,到处都是大师封装好的精美绝伦的指针。为了更容易的讲解Java中关于类和类型的调用, Java中出现了值与引用的说法。浅显的来说,我们可以认为 Java中的引用与 C 中的指针等效(其实差别非常非常大,但是为了说明我们今天的问题,把他们理解为等效是没有任何问题的)。 所谓传引用的说法是为了更好的讲解调用方式。基于上面对指针的理解,我们不难看出,指针其实也是一个 int值,所谓传引用,我们是复制了复制了指针的 int值进行传递。为了便于理解,我们可以姑且把指针看作一种数据类型,透明化指针的 int特性,从而提出传引用的概念。 重申一

3、遍: Java中只有传值。 1 所谓传值和传引用 传值和传引用的问题一直是 Java里争论的话题。与 C+不同的, Java里面没有指针的概念, Java的设计者巧妙的对指针的操作进行了管理。事实上,在懂 C+的 Java程序员眼中, Java到处都是精美绝伦的指针。 下面举个简单的例子,说明什么是传值,什么是传引用。 /例 1 void method1() int x=0; this.change(x); System.out.println(x); void int change(int i) i=1; 很显然的,在 mothod1中执行了 change(x)后, x 的值并不会因为 ch

4、ange方法中将输入参数赋值为 1 而变成 1,也就是说在执行 change(x)后, x 的值 z 依然是 0。这是因为 x 传递给 change(int i)的是值。这就是最简单的传值。 同样的,进行一点简单的变化。 /例 2 void method1() StringBuffer x=new StringBuffer(“Hello“); this.change(x); System.out.println(x); 2void int change(StringBuffer i) i.append(“ world!“); 看起来没什么变化,但是这次 mothed1中执行了 change (

5、x)后, x 的值不再是 “Hello“了,而是变成了 “Hello world!“。这是因为x 传递给 change(i)的是 x 的引用。这是最经典的传引用。 似乎有些奇怪了,两段程序没有特别的不同,可是为什么一个传的是值而另一个传的是引用呢? 2 非要搞清楚传值还是传引用的问题吗? 搞清楚这自然是有必要的,不然我也不需要写这么多了,不过的确没有到 “非要 “的地步。 首先,如果我们不太关心什么是传值什么是传引用,我们一样能写出漂亮的代码,但是这些代码在运行过程中可能会存在着极大的隐患。 全局变量是让大家深恶痛绝(又难以割舍)的东西,原因就是使用全局变量要特别注意数据的保护。如果在多线程的

6、程序里使用全局变量简直就等于跟自己过不去。不了解传值和传引用的问题,跟使用全局变量不考虑数据保护的罪过是不相上下下的,甚至有时候比它还要糟。你会莫名其妙,为什么我的返回参数没有起作用,为什么我传进去的参数变成了这样 ? 一个例子: /例 3 void mothed1() int x=0; int y=1; switchValue(x,y); System.out.println(“x=“+x); System.out.println(“y=“+y); void switchValue(int a,int b) int c=a; a=b; b=c; 上面是一个交换 a,b值的函数,看起来似乎蛮正

7、确的,但是这个函数永远也不会完成你想要的工作。 还有一个例子: /例 4 StringBuffer a=new StringBuffer(“I am a “); StringBuffer b=a; a.append(“after append“); a=b; System.out.println(“a=“+a); 在编程过程中,经常会遇到这种情况,一个变量的值要被临时改变一下,等用完之后再恢复到开始的值。就好像上面的例子,a 为了保持它的值,使用 b=a做赋值,之后 a 被改变,再之后 a 把暂存在 b 里面的值取回来。这是我们一厢情愿的想法,而事实上,这段代码执行后,你会发现 a 的值已经改

8、变了。 以上是两个最简单的例子,真正的程序开发过程中,比这要复杂的情况每天都会遇到。 3 类型和类 3Java 提出的思想,在 Java里面任何东西都是类。但是 Java里面同时还有简单数据类型: int,byte,char,boolean,与这些数据类型相对应的类是 Integer, Byte, Character, Boolean,这样做依然不会破坏 Java关于任何东西都是类的提法。 这里提到数据类型和类似乎和我们要说的传值和传引用的问题无关,但这是我们分辨传值和传引用的基础。 4 试图分辨传值还是传引用 为什么是 “试图分辨 “呢?很简单,传值和传引用的问题无处不在,但是似乎还没有人能

9、正统的给出标准,怎样的就是值拷贝调用,怎样的就是引用调用。面对这个问题,我们更多的应该是来自平时积累对 Java的理解。 回过头来,我们分析一下上面的几个例子: 先看例 1,即使你不明白为什么,但是你应该知道这样做肯定不会改变 x 的值。为了方便说明,我们给例子都加上行号。 /例 1 1 void method1() 2 int x=0; 3 this.change(x); 4 5 6 void int change(int i) 7 i=7; 8 让我们从内存的存储方式看一下 x 和 I 之间到底是什么关系。 在执行到第 2 行的时候,变量 x 指向一个存放着 int 0 的内存地址。 变量

10、 x-存放值 0 执行第 3 行调用 change(x)方法的时候,内存中是这样的情形: x 把自己值在内存中复制一份,然后变量 i 指向这个被复制出来的 0。 变量 x-存放值 0 进行了一次值复制 变量 x-存放值 0 这时候再执行到第 7 行的时候,变量 i 的被赋值为 7,而这一步的操作已经跟 x 没有任何关系了。 变量 x-存放值 0 变量 x-存放值 7 说到这里应该已经理解为什么 change(x)不能改变 x 的值了吧?因为这个例子是传值的。 那么,试着分析一下为什么例三中的 switchValue()方法不能完成变量值交换的工作? 再看例 2。 /例 2 1void meth

11、od1() 2 StringBuffer x=new StringBuffer(“Hello“); 43 this.change(x); 4 5 6void int change(StringBuffer i) 7 i.append(“ world!“); 8 例 2 似乎和例 1 从代码上看不出什么差别,但是执行结果却是 change(x)能改变 x 的值。依然才从内存的存储角度来看看例 2的蹊跷在哪里。 在执行到第 2 行时候,同例 1 一样, x 指向一个存放 “Hello“的内存空间。 变量 x-存放值 “Hello“ 接下来执行第三行 change(x),注意,这里就与例 1 有了本

12、质的不同:调用 change(x)时,变量 i 也指向了 x 指向的内存空间,而不是指向 x 的一个拷贝。 变量 x 存放值 “Hello“ 变量 x / 于是,第 7 行对 i 调用 append方法,改变 i 指向的内存空间的值, x 的值也就随之改变了。 变量 x 追加为 “Hello World!“ 变量 x / 为什么 x 值能改变呢?因为这个例子是传引用的。 这几个例子是明白了,可是很多人会开始有另一个疑问了:这样看来,到底什么时候是传的值什么时候是传得引用呢?于是,我们前面讲到的类型和类在这里就派上了用场:对于参数传递,如果是简单数据类型,那么它传递的是值拷贝,对于类的实例它传递

13、的是类的引用。需要注意的是,这条规则只适用于参数传递。为什么这么说呢?我们看看这样一个例子: /例 5 String str=“abcdefghijk“; str.replaceAll(“b“,“B“); 这两句执行后, str的内容依然是 “abcdefghijk“,但是我们明明是对 str操作的,为什么是这样的呢?因为 str的值究竟会不会被改变完全取决于 replaceAll这个方法是怎么实现的。类似的,有这样一个例子: /例 6 1 void method1() 2 StringBuffer x = new StringBuffer(“Hello“); 3 change1(x); 4

14、System.out.println(x); 5 6 7 void method2() 8 StringBuffer x = new StringBuffer(“Hello“); 9 change2(x); 510 System.out.println(x); 11 12 13 void change1(StringBuffer sb) 14 sb.append(“ world!“); 15 16 17 void change2(StringBuffer sb) 18 sb = new StringBuffer(“hi“); 19 sb.append(“ world!“); 20 调用 met

15、hod1(),屏幕打印结果为: “Hello world!“ 调用 method2(),我们认为结果应该是 “hi world“,因为 sb传进来的是引用。可是实际执行的结果是 “Hello“! 难道 change2()又变成传值了?!其实 change1()和 change2()的确都是通过参数传入引用,但是在方法内部因为处理方法的不同而使结果大相径庭。我们还是从内存的角度分析: 执行 method1()和 change1()不用再多说了,上面的例子已经讲解过,这里我们分析一下 method2()和 change2()。 程序执行到第 8 行, x 指向一个存放着 “Hello“的内存空间。

16、 变量 x-存放值 “Hello“ 第 9 行调用 change2,将 sb指向 x 指向的内存空间,也就是传入 x 的引用。 变量 x 存放值 “Hello“ 变量 x / 到这里为止还没有什么异样,接下来执行 18行,这里就出现了类似传入值拷贝的变化: new 方法并没有改变 sb指向内存的内容,而是在内从中开辟了一块新的空间存放串 “hi“,同时 sb指向了这块空间。 变量 x-存放值 “Hello“ 原有的引用被切断 变量 x-另一块存放 “hi“的空间 接下来再对 sb进行 append已经和 x 没有任何关系了。 所以,还有一条不成规则的规则:对于函数调用,最终效果是什么完全看函数

17、内部的实现。比较标准的做法是如果会改变引用的内容,则使用 void作为方法返回值,而不会改变引用内容的则在返回值中返回新的值。 虽然已经说了这么多,但是感觉传值还是传引用的问题依然没有完全说清楚。因为这个问题本身就是很难归纳总结的问题,所以更多的理解要靠平时的积累和形成。下面几个例子,给大家尝试进行分析。 /例 7,打印结果是什么? public static void main(String args) int a; int b; StringBuffer c; StringBuffer d; 6a = 0; b = a; c = new StringBuffer(“This is c“);

18、 d = c; a = 2; c.append(“!“); System.out.println(“a=“ + a); System.out.println(“b=“ + b); System.out.println(“c=“ + c); System.out.println(“d=“ + d); /例 8,打印结果是什么? public class Test public static void main(String args) StringBuffer sb = new StringBuffer(“Hello “); System.out.println(“Before change,

19、sb = “ + sb); changeData(sb); System.out.println(“After changeData(n), sb = “ + sb); public static void changeData(StringBuffer strBuf) StringBuffer sb2 = new StringBuffer(“Hi “); strBuf = sb2; sb2.append(“World!“); 如果是以基本数据类型(包括 String 类)做参数进行传递,或以某个类名(包括数组名)为类型做为参数而直接对其类进行操作(非类的属性),这样的传递叫值传递;如果是以某个类名为类型做为参数进行传递而针对该类的属性进行的操作,这样的传递叫做引用传递。也就是说在值传递的过程中其操作不会对所传进来的对象有任何的影响,它传进来的只是该对象的一个副本,其本身不会有任何的改变;而引用传递则传进来的是该对象的一个别名,即引用该对象在虚拟机中的“地址”,因此引用传递会对该“地址”的内部属性产生影响,而不会改变该“地址”在虚拟机中的位置,即引用传递在外部看来是没有发生过任何变话的,但从内部看来,它的属性会随着调用它的方法的改变而改变因此,也有人说 JAVA 只有“值传递”,而没有引用传递

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报