`

@Marked-关于java值传递的问题,图解直观,若您有有高见请斧正!

    博客分类:
  • Java
阅读更多

 两段代码,结果的差异,请结合代码给图解下内存和执行过程。
  万分感谢!

    public class PassAddr {  
        public static void main(String[] args) {  
            String s=new String("old");  //1
            method(s);  //3
            System.out.println(s);  
        }  
        static void method(String str){  
            str=new String("new");  //2
        }  
    }  

这个输出结果为:old

    public class T { 
        public static void main(String[] args) { 
            String[] arr=new String[2]; 
            arr[0]="old_0"; 
            arr[1]="old_1"; //11    
         /*arr[0]=new String("old_0"); 
            arr[1]=new String("old_1"); //11 同样*/
            method(arr); //14
            System.out.println(arr[0]+";"+arr[1]); 
        } 
        static void method(String[] a){//12 
                a[0]="new_0"; 
                a[1]="new_1"; //13
            } 
    } 

 

这个输出却是:new_0;new_1
-------------------------------------------

自己发的问题,想了半天想通了。解析下,希望各位斧正!
===================================

string://1处时:

//1处时候

//2处时:

//2处时候

//3处:

由于方法调用已经完成,所以str临时变量在stack中消失,s还是0x001,其地址处对象new String("old")没有被动;所以输出结果还是old;

---------------------------------------------------固执的分割线------------------------------------------------------

//11处内存状态:

//11处

//12处:

//12处

//13处时候的内存状况:

//13处

此时a[0]和a[1]的值被改变,其实就是arr的相应值改变了。最后就出现了结果如图://14

//14

所以就出现结果改变的情况了。

这么一作图,很直观了。

分享到:
评论
30 楼 淫笑琪 2011-09-24  
其实没什么,是你画图画太乱了。第一个例子字符串之所以值没变是因为字符串的不可变性,第2个是数组自然就变了
29 楼 boy00fly 2011-06-29  
<div class="quote_title">dotjar 写道</div>
<div class="quote_div">
<p> 两段代码,结果的差异,请结合代码给图解下内存和执行过程。<br>
  万分感谢!</p>
<pre name="code" class="java">    public class PassAddr { 
        public static void main(String[] args) { 
            String s=new String("old");  //1
            method(s);  //3
            System.out.println(s); 
        } 
        static void method(String str){ 
            str=new String("new");  //2
        } 
    }  </pre>
<p>
这个输出结果为:old</p>
<pre name="code" class="string array">    public class T {
        public static void main(String[] args) {
            String[] arr=new String[2];
            arr[0]="old_0";
            arr[1]="old_1"; //11    
         /*arr[0]=new String("old_0");
            arr[1]=new String("old_1"); //11 同样*/
            method(arr); //14
            System.out.println(arr[0]+";"+arr[1]);
        }
        static void method(String[] a){//12
                a[0]="new_0";
                a[1]="new_1"; //13
            }
    } </pre>
<p> </p>
<p>这个输出却是:new_0;new_1<br>
-------------------------------------------</p>
<p>自己发的问题,想了半天想通了。解析下,希望各位斧正!<br>
===================================</p>
<p>string://1处时:</p>
<p><img src="/upload/picture/pic/93186/16e35de7-0591-3acf-b994-3ecfd094072a.jpg" alt="//1处时候" width="466" height="304"></p>
<p>//2处时:</p>
<p><img src="/upload/picture/pic/93188/109d37bf-91fb-369c-bc30-33767ad5efad.jpg" alt="//2处时候" width="484" height="303"></p>
<p>//3处:</p>
<p>由于方法调用已经完成,所以str临时变量在stack中消失,s还是0x001,其地址处对象new String("old")没有被动;所以输出结果还是old;</p>
<p>---------------------------------------------------固执的分割线------------------------------------------------------</p>
<p>//11处内存状态:</p>
<p><img src="/upload/picture/pic/93190/5add0c4c-7ef7-3d73-8320-93e429f56b91.jpg" alt="//11处" width="532" height="305"></p>
<p>//12处:</p>
<p><img src="/upload/picture/pic/93192/2f26462a-09e4-3db6-acdb-8671fe32db37.jpg" alt="//12处" width="545" height="295"></p>
<p>//13处时候的内存状况:</p>
<p><img src="/upload/picture/pic/93194/16389c1f-85b8-3c81-8337-9e7948282110.jpg" alt="//13处" width="545" height="304"></p>
<p>此时a[0]和a[1]的值被改变,其实就是arr的相应值改变了。最后就出现了结果如图://14</p>
<p><img src="/upload/picture/pic/93196/db5977eb-3f16-3e36-af73-79ef2f68c677.jpg" alt="//14" width="525" height="294"></p>
<p>所以就出现结果改变的情况了。</p>
<p>这么一作图,很直观了。</p>
</div>
<p>楼主分析的完全正确!!!<img src="/images/smiles/icon_idea.gif" alt=""></p>
28 楼 dotjar 2011-06-29  
JE帐号 写道
... ...
两段代码,又不相似.没什么可对比的,如果第二段代码的method方法为以下
static void method(String[] a){//12   
   a = new String[]{"1","2"};
} 

在这种情况下如果两段代码结果表现不一样,才有意思.
现在你两个例子里,一个是对传入的参数进行=操作,另一个是对传入的参数里的元素进行=操作.这又什么好对比的?

结果也是变化了啊,有什么意思?
27 楼 coolcooldool 2011-06-29  
JE帐号 写道
... ...
两段代码,又不相似.没什么可对比的,如果第二段代码的method方法为以下
static void method(String[] a){//12   
   a = new String[]{"1","2"};
} 

在这种情况下如果两段代码结果表现不一样,才有意思.
现在你两个例子里,一个是对传入的参数进行=操作,另一个是对传入的参数里的元素进行=操作.这又什么好对比的?


你第二个调用new 和第一个一样了。
26 楼 gtssgtss 2011-06-29  
kingkan 写道
i.phoenix 写道
TO bugmenot:

String确实是传值的,虽然它是普通的对象。在方法中,对传入的String变量做了任何操作,返回到调用者那儿,那个String还没有变。



String是final类。。。

方法调用时,JVM会把String的引用值复制到方法栈中执行。而对于在方法栈中对该引用值作何改动都不会影响主线程的String变量在堆中的值。

数组在Java中是一个对象,而数组类型只不过是相当于对象中的属性而已,与String无关。

楼主对于Java程序在JVM的堆栈中运行过程理解非常清晰,各位不懂的同学真的可以学习下。


和final没关系。。。final只是不能继承


ps:如果说String的属性是final的,那还是没用。
final只是属性的值不变,field本身是否会改变要另外考虑,如果field里面的值(包括的值的值的值。。。)都是不变,那这个对象才是在普通情况完全不变(别扯字节码甚至直接操作内存啥的)
抱歉的是string里的value巧好是个数组,而恰好数组里面的值java没给我们final这个选项

public static void main(String [] a) throws Exception{
		String aa = "iteye";
		System.out.println(aa);
		changeString(aa, "csdn");
		System.out.println(aa);
	}
	
	public static void changeString(String dst,String src) throws Exception{
		Field value = String.class.getDeclaredField("value");
		value.setAccessible(true);
		char[] valueA = (char[])value.get(dst);
		char[] valueB = (char[])value.get(src);
		System.arraycopy(valueB, 0, valueA, 0, Math.min(valueA.length, valueB.length));
	}
25 楼 116427 2011-06-29  
在java方法中不管传给形参的实参是基本类型,还是对象类型,

形参的操作都不能改变传入的实参的值(可以把这个值理解为内存中的地址)

但是形参可以持有实参传过来的这个值(就如同楼主画图分析的那样),

形参一旦持有实参传过来的值就可以改变实参对象本身的属性,

并且形参所持有的值是可以改变的(即可以指向其他对象),但是如果形参设置为final则形参不能再指向其他对象!

所以在方法中要区分出形参进行的是那种操作

总结:java中都是值传递!很奇怪为什么不叫引用传递呢?

理解不够准确,还请各位指出来
24 楼 kyan54 2011-06-29  
haidii 写道
so easy
java的对象都是引用。
第一个只是把引用的地址改了,原来的字符串没变。
第二个是数组,数组是直接引用地址。
就这么简单。



就是这么简单。。。
23 楼 i.phoenix 2011-06-29  
讨论得很好,学习了^-^...
22 楼 kingkan 2011-06-29  
i.phoenix 写道
TO bugmenot:

String确实是传值的,虽然它是普通的对象。在方法中,对传入的String变量做了任何操作,返回到调用者那儿,那个String还没有变。



String是final类。。。

方法调用时,JVM会把String的引用值复制到方法栈中执行。而对于在方法栈中对该引用值作何改动都不会影响主线程的String变量在堆中的值。

数组在Java中是一个对象,而数组类型只不过是相当于对象中的属性而已,与String无关。

楼主对于Java程序在JVM的堆栈中运行过程理解非常清晰,各位不懂的同学真的可以学习下。
21 楼 i.phoenix 2011-06-28  
TO bugmenot:

String确实是传值的,虽然它是普通的对象。在方法中,对传入的String变量做了任何操作,返回到调用者那儿,那个String还没有变。

20 楼 zhangdaweizdw1 2011-06-28  
java 对象的传递中,改变不了对象本身,但是能改变对象的属性元素
19 楼 shanga 2011-06-28  
<div class="quote_title">dotjar 写道</div>
<div class="quote_div">
<p> 两段代码,结果的差异,请结合代码给图解下内存和执行过程。<br>
  万分感谢!</p>
<pre name="code" class="java">    public class PassAddr { 
        public static void main(String[] args) { 
            String s=new String("old");  //1
            method(s);  //3
            System.out.println(s); 
        } 
        static void method(String str){ 
            str=new String("new");  //2
        } 
    }  </pre>
<p>
这个输出结果为:old</p>
<pre name="code" class="string array">    public class T {
        public static void main(String[] args) {
            String[] arr=new String[2];
            arr[0]="old_0";
            arr[1]="old_1"; //11
            method(arr); //14
            System.out.println(arr[0]+";"+arr[1]);
        }
        static void method(String[] a){//12
                a[0]="new_0";
                a[1]="new_1"; //13
            }
    } </pre>
<p> </p>
<p>这个输出却是:new_0;new_1<br>
-------------------------------------------</p>
<p>自己发的问题,想了半天想通了。解析下,希望各位斧正!<br>
===================================</p>
<p>string://1处时:</p>
<p><img src="/upload/picture/pic/93186/16e35de7-0591-3acf-b994-3ecfd094072a.jpg" alt="//1处时候" width="466" height="304"></p>
<p>//2处时:</p>
<p><img src="/upload/picture/pic/93188/109d37bf-91fb-369c-bc30-33767ad5efad.jpg" alt="//2处时候" width="484" height="303"></p>
<p>//3处:</p>
<p>由于方法调用已经完成,所以str临时变量在stack中消失,s还是0x001,其地址处对象new String("old")没有被动;所以输出结果还是old;</p>
<p>---------------------------------------------------固执的分割线------------------------------------------------------</p>
<p>//11处内存状态:</p>
<p><img src="/upload/picture/pic/93190/5add0c4c-7ef7-3d73-8320-93e429f56b91.jpg" alt="//11处" width="532" height="305"></p>
<p>//12处:</p>
<p><img src="/upload/picture/pic/93192/2f26462a-09e4-3db6-acdb-8671fe32db37.jpg" alt="//12处" width="545" height="295"></p>
<p>//13处时候的内存状况:</p>
<p><img src="/upload/picture/pic/93194/16389c1f-85b8-3c81-8337-9e7948282110.jpg" alt="//13处" width="545" height="304"></p>
<p>此时a[0]和a[1]的值被改变,其实就是arr的相应值改变了。最后就出现了结果如图://14</p>
<p><img src="/upload/picture/pic/93196/db5977eb-3f16-3e36-af73-79ef2f68c677.jpg" alt="//14" width="525" height="294"></p>
<p>所以就出现结果改变的情况了。</p>
<p>这么一作图,很直观了。</p>
</div>
<p>两个例子没有对比性,str在方法new了,而数组没有在方法内new</p>
18 楼 吖吖邦 2011-06-28  
其实只要弄清楚
String ss = "abc";

String sss = new String("abc")
的区别就很容易理解了
17 楼 sbli27 2011-06-28  
如果你愿意欣赏汇编的话,你会发现,本来就应该是这样的
16 楼 chashui 2011-06-28  
对象和值,对象是引用,值是赋值
15 楼 fengyexjtu 2011-06-28  
haidii 写道
so easy
java的对象都是引用。
第一个只是把引用的地址改了,原来的字符串没变。
第二个是数组,数组是直接引用地址。
就这么简单。

正解.
14 楼 bugmenot 2011-06-28  
i.phoenix 写道
JE帐号 写道
... ...
两段代码,又不相似.没什么可对比的,如果第二段代码的method方法为以下
static void method(String[] a){//12   
   a = new String[]{"1","2"};
} 

在这种情况下如果两段代码结果表现不一样,才有意思.
现在你两个例子里,一个是对传入的参数进行=操作,另一个是对传入的参数里的元素进行=操作.这又什么好对比的?

是呀,Java对象、简单类型的数组均是传址的,简单类型(含string)都是传值的。这个不难理解。用过C语言指针的理解起来无须费力。还画个图搞这么复杂干嘛呀?

String跟普通引用类型完全一样。大大自己的理解就是错的还说别人么
13 楼 bommeibo 2011-06-28  
brown802 写道
发的文章不进行过滤吗?两段代码根本没有可比性啊!

的确,2段代码中处理的方式都不一样,一个是new,一个是重新赋值。
12 楼 javabkb 2011-06-28  
牢记pass by value就行了吧,这个应该不用分析堆栈的吧
11 楼 brown802 2011-06-28  
发的文章不进行过滤吗?两段代码根本没有可比性啊!

相关推荐

Global site tag (gtag.js) - Google Analytics