刚又看了个帖子,关于java参数传递的。我不认为我把这个问题彻底搞明白了,但我坚信真正搞明白这个问题的同学应该是屈指可数的。先看几个问题吧,希望明白的和不明白的同学都回复下,大家共同把这个问题搞明白。1int a = 1;
int b = a;
b = 2;
System.out.println("a=" + a);
System.out.println("b=" + b);如果有人觉得这个不像是参数传递那么我们写成下面的形式:public static void change(int b) {
b = 2;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int a = 1;
change(a);
System.out.println("a=" + a); }
2 和1差不多,我们换成String 来看看,String可不是基本类型哦。
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1 = "abc";
String s2 = s1;
s2 += "d";
System.out.println("s1=" + s1);
System.out.println("s2=" + s2); }
如果认为这不叫参数传递可以像1那样修改下。
public static void change(String s2) {
s2 += "d";
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1 = "abc";
change(s1);
System.out.println("s1=" + s1); }3 最后看下引用类型或是说非基本类型再或者是对象类型,以int数组来举例。int[] a = new int[1];
a[0] = 1;
int[] b = a;
b[0] = 2;
System.out.println("a[0]=" + a[0]);
System.out.println("b[0]=" + b[0]);
同样可以做上面的修改:
public static void change(int[] b) {
b[0] = 2;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] a = new int[1];
a[0] = 1;
change(a);
System.out.println("a[0]=" + a[0]); }
请大家就上面3段代码的结果给出理由。
int b = a;
b = 2;
System.out.println("a=" + a);
System.out.println("b=" + b);如果有人觉得这个不像是参数传递那么我们写成下面的形式:public static void change(int b) {
b = 2;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int a = 1;
change(a);
System.out.println("a=" + a); }
2 和1差不多,我们换成String 来看看,String可不是基本类型哦。
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1 = "abc";
String s2 = s1;
s2 += "d";
System.out.println("s1=" + s1);
System.out.println("s2=" + s2); }
如果认为这不叫参数传递可以像1那样修改下。
public static void change(String s2) {
s2 += "d";
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1 = "abc";
change(s1);
System.out.println("s1=" + s1); }3 最后看下引用类型或是说非基本类型再或者是对象类型,以int数组来举例。int[] a = new int[1];
a[0] = 1;
int[] b = a;
b[0] = 2;
System.out.println("a[0]=" + a[0]);
System.out.println("b[0]=" + b[0]);
同样可以做上面的修改:
public static void change(int[] b) {
b[0] = 2;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] a = new int[1];
a[0] = 1;
change(a);
System.out.println("a[0]=" + a[0]); }
请大家就上面3段代码的结果给出理由。
2、s1=abc。 理由:引用传递。对象“abc”由引用s1指向。传入方法change后,该对象有两个引用指向他。一个是s1,另一个是局部变量s2。s2 += "d";操作返回一个新的对象“abcd”,由局部变量s2指向他。而原来的“abc”对象的引用由原来的s1指向没有变。
3、a[0]=2。理由:引用传递。 a指向数组A;0位被赋予1的值。该引用作为参数传入方法change里。
局部变量b指向数组A;并对0位的值作修改,赋值为2。再用a取数组A的0位,值自然变成2了
2:String是个特殊的,只要给String新的值或者加值,JVM都会分配新的内存空间,
String s1 = "abc";
JVM给s1分配的内存空间假如是a,当你把s1传给方法也就是s2 += "d";
时JVM会给s2重新分配空间,但s1还是指向a空间
第二段代码 String 是引用类型,但是他比较特殊, b=a 实际上输出a的值就是b变量的值
第三段代码 数组时引用类型 声明变量的时候 保存在栈中 但是一旦遇到new关键字 就会在堆内存中开辟一块空间并且把地址赋值给变量a int[] a = new int[1];
如果b=a 的话 实际上就是把a空间(栈)里的地址给了b空间(栈) a,b空间保存的地址引用的是同一个内存堆中的空间数据
这个是我的理解
1.我想问你下,你认为1的两种写法实质一样么?
2.为什么会返回一个新的对象"abcd".而3中却不返回一个新的数组对象呢?
理由:要理解一点,对基本数据类型的操作,都是操作的他的副本,也就是他的拷贝.首先a不用说.当执行int b = a 就是一个彻头彻尾的普通赋值方法.然后b =2 即将b的值进行改写.这个我觉得没什么可解释的.
至于调用change(a);就不一样了.前面说过:对基本数据类型的操作,都是操作的他的副本.所以此处可以理解为传过去的是a的拷贝.更重要我觉得是一个作用域的问题.如果你把a作为全局变量,然后在change方法里对c进行修改试试.当然如果改成全局变量,又想在main函数里使用.肯定要改成static的,这又不一样了.而且我觉得你这样转换不是等价的...很牵强.
2>首先字符串是不可变对象.是一个比较特殊的对象.首先s1指向字符串池中一块值为"abc"的区域,然后你对s2= s1 + "d"; 因为不可变.所以他会重新产生一块内存区..所以打印出来s1="abc" s2="abcd"毫无疑问
3>打印1和2.楼主我觉得你没想明白的主要原因是你不知道:首先对一个变量直接进行赋值和对他进行运算操作.是不同的概念..操作的永远都只是他的拷贝...但是如果是static的变量就不一样.而字符串列你可以把他理解为一个常量,一旦定义不可更改..
而且我觉得你的改写和你没必写之前要表达的意思不一样..如果非说一样,我觉得很牵强
[/
public static void change(String a) {
a = "aa";
}
public static void changeBuffer(StringBuffer a) {
a.append("a");
}
public static void main(String[] args) {
String b = "b";
change(b);
StringBuffer c = new StringBuffer("c");
changeBuffer(c);
System.out.print(b);
System.out.print(c);
}
你的意思是 b=a 的时候会在内存中再放入一个1,JVM真的是这样做的吗?你从什么来确定的。
2 你说到了字符串池,那你对常量池有了解吗,这两个有什么关系知道吗?
方法里的变量都是局部变量;作用区域在方法内。但该局部引用变量所指向的对象如果是可修改的;那就可以修改;方法指向该对向的引用得到的是修改后的结果。String是不可修改的。所以s1指向那个对象就是那个对象
amos1989 再问你下吧,有没有想过:
int a = 1;
int b=1;
a=b 是ture 的实质是什么呢?
他和
String s1 = "abc";
String s2 = "abc";
s1=s2
是否有什么联系、
3、引用副本,理由,也是JAVA规定,非基本类型的都是这样,也是没什么好说2、类似1,理由,String是特殊类,String底层是由char[]构成,JAVA的JVM也有个字符串池,其实说明白点String还是类,不过它是由char[]数组组成,不过这些实例不由我们操作,由JVM的自己处理,所以当我们使用String s = "";的时候,JVM在后面已经帮我作了一些判断,到底是new呢还是返回已有值
总的来说2,可以看成基本类型使用,但要心底记着,它其实还是个类,只不过JVM做了我们不知道的处理以上是我愚昧的理解
只是引用可以指向一段地址;如果这段地址可修改;并且在方法里被修改过了。那么方法外指向这段地址的引用就得到了修改后的结果。String的特殊在于它不可修改。
int a = 1;
int b=1;
a=b
得到启发。很高兴能和你讨论,但是你的回答让我不满意哦,呵呵。
int j = i;//这里就把i引用指向10的这个值,复制(副本)到j引用上去所以当你操作i的时候,和j是没关系的
2.String 类型和基本类型不同
在我的印象中String类型赋值的话他会放弃自己引用的空间而从新开辟一块新的空间来被赋值
如果String s="abc";
s+="def";
在我的印象中是abc这个空间就别仍掉了,会从新开一个空间,给这个s赋值 而这个s是个新的引用空间 这个是我的理解 可能不正确
假设是复制地址。
那么1中
public static void change(int b) {
b = 2;
}
b就指向了这个地址。并且修改了这个地址的值。
与结果不符。那么剩下就是复制值了。
b改变的是复制的值,与本身没有影响。
我想起了一个问题..
请看如果一段代码,如果不在eclipse里运行,请写出输出结果 public static void main(String[] args) {
int j = 0;
for(int i = 0; i < 100 ; i ++){
j = j ++;
}
System.out.println(j); }
你看下答案是什么?
或者人类灭绝了
不然过段时间又会冒出来D。。
b=2时,因为b之前指向了1,当改变 =2 是 ,jvm首先会到栈中查找是否有2,如果有,就将b指向2,如果没有就在栈中放2 然后 b指向2,而原来的 引用a 和 栈中的1 都没有变化。我有一点可以证明这个观点,就是我上面说的:
int a = 1;
int b = 1;
a=b
复杂类型传引用。如果你修改对象内的值(例如调用set方法),外部是受影响的。如果用=直接操作对象,还是引用传递,外部不受影响。别拿String说事,因为不可变,可以当它是基本类型看待了。
public static void main(String[] args) {
int j = 0;
for (int i = 0; i < 100; i++) {
j = ++j;
}
System.out.println(j); }
还是这个程序.
public static void main(String[] args) {
int j = 0;
for(int i = 0; i < 100 ; i ++){
j = j ++;
}
System.out.println(j);}如果按照你的分析,那么输出的是100,但实际上输出的肯定是0.
同样,在你对基本数据类型进行操作后,他会生成在内存中划分出另外一块内存区.首先刚开始J = 0 , 在J = J++的时候, 等号前面的那个J已经不是J声名时的那块内存区了,JVM为他重
新为他分配一块新的内存区.也就是入栈..比如说,int j = 0 时,j的内存地址为00xx01,值为0。那么经过第一循环的以后前面那个J内存地址为00xx02,值为0,而后面那个J(内存地址00xx01)则会进行++操作,此时他的值为1,不过他已经不能影响到前面J的值了,此时J的内存地址就已经是等号前面的那个J的内存地址了(00xx02),再进行第二循环的时候,j的内存地址是:00xx02,值是0,至于00xx01那块内存区域,因为已经没有人再使用,所以将会在下一次垃圾回收的时候被GC回收,此时他(内存地址为00xx02的J)变成后面的那个j,前面那个J 则又会重新分得一块新的内存区域00xx03,值仍然是0,而00xx02则又会被丢弃然后被GC回收,依此类推,直至最后打印时J仍然为0,但他的内存地址已经不是最开初的00xx01了,换句话说,他已经不是当初的那个J了。
或者你改成
public static void main(String[] args) {
int j = 0;
for (int i = 0; i < 100; i++) {
j += 1;
}
System.out.println(j); }
再看看。
或许你可以帮我解释下:
int a = 1;
int b= 1;
a=b
的问题。非常感谢。
而后面那个J(内存地址00xx01)则会进行++操作,此时他的值为1,
其实这个时候后面那个J还不是1哦。记住j++是先赋值再做运算。所以你这里不管怎么循环j都是0.你认同我的观点吗?
所以我们可以把他们理解为:现在有2个盒子a,b.里面都装着一个1. 当他们进行a==b的比较操作时,实际上去取出他们盒子里面的东西出来进行比较
先把后面那个J的值拷一份给前面那个J.然后对后面内在地址中的J+1
建议自己画个内存示意图,其实很容易懂。
有兴趣的可以去翻一下《Core Java》,有图有真相。
j =j++
那么我问你,j++肯定是执行了对不对? 只不过是在赋值以后执行的.
如果变量进行基本操作的时候,不是对变量进行复制..
那么前面的那个j和后面那个j就是同一个内存地址.那么即使是先把后面的j的值赋给前面的j,再对后面的j进行++操作,那么由于他们是一个内存地址,其实前面j的值还是发生了改变对不对??? 那么第二次循环的时候他就不再为0了.可是你打印一下,每次循环他都是0.说明他们不是同一个内存地址对不对??既然是同一个变量,却又不是同一个内存地址?怎么解释?除了复制这种解释外..
为什么不尝试着用我的这种思维方式想一下列?? 一定要先入为主?
int a = 1;
int b = a;
b=2;
其实说来说去,问题的关键是在这里:
你们的看法:
在int b = a;的时候,就已经对1进行了复制。
然后在 b=2;时改变b指向的1=2;而我的看法:
int b = a;的时候并没有对1进行复制。
而是在 b=2的时候,向栈中直接添加2,再让b指向2.
大家可以对比两种做法对内存的耗费情况和操作的复杂度,我相信JVM的设计者是明智的!
第1题第2段,在
b = 2;
的下边在加一个输出
System.out.println("a=" + b);
再看结果就很明显了,b = 2 这句里的变量b是在change方法里产生的,那作用范围也就只是在change里。
大兔子大概能再下个结论了吧
你说a==b这问题嘛,还是要分角度说下去
我们说专业点,用OO的角度来说,是相等的,不过只限于基本类型
要是按C、汇编…………等等角度来说,问是根据地址相等还是值相等,不同JVM有不同的做法,可能某天SUN(还是应该说是Oracle呢)觉得这样效果不好,用一种新方式作判断那么到时候又是一大片的讨论所以这个既然JAVA说是OO编程,我们就看着OO来做事
至于底层怎么实现,用OO来说,觉得也不太现实,底层的问题还是C++、C、汇编吧(虽然这2门我都没学过)
你我都不是JVM的设计者,不过是找一个合适的解释方式,让自己的想法说得过去..
JAVA中有规定,基本数据类型 == 比较的是两个变量的值.而不是地址..无意冒犯,但是如果你连这个都没搞清楚那我白跟你讨论了。
-------> 你看清楚.我是怎么说的....自己要钻牛角尖..你就继续钻...
看楼上那些人还鸟你....没意义的..如果JVM是你设计的..你说什么我都相信...
无意冒犯...就看不惯人老钻牛角尖..
所以change(int i){
i = 100;
}
对 i 是没什么影响的
而 change(Object o){
o.attribute
}
则改变了 o 的属性值 但 o 本身的值(即地址) 是不会有任何改变的
说到底 Java 还是有指针的 引用就是
Java也不是纯粹的面向对象,几个基本数据类型就很尴尬
所有后来jdk5.0 就有封箱解箱了
说说就要到内存的分配了,就此打住
第二,好让JAVA语言搞点“特色”
第三,要是把基本类型抹了要是别人问你,C++和JAVA你说一个面向过程,一个面向对象,有啥区别啊,大家还不是一样写一堆类一堆变量一堆…………
第四,个人来说已经习惯JAVA这么个思维了,就放过我吧
如果没有,那我们能确切的知道JVM对于这个问题是怎么设计的???
如果不能.那么只不过是给自己找一个适合的解释,去说通这个问题...
如果非要这样争下去...跟讨论先有鸡还是先有蛋有区别吗???有些问题,适可而止.
如果你说为了研究学术...我无语可说,但我要说的是有必要吗???
如果要搞清楚SSH的具体实现?我们不是原理性理解,应用熟练就行???莫不成你还要去写一个SSH出来?? 语言说到底就是一个工具,用JAVA也好,C也好.我们只不过是做开发.不是做研究.何况对于不同的系统
JVM也有不同的实现..
就像平时我们写算法,对于同一问题,可能就多种算法. 你个人肯定会偏向于一种.如果这个算法题让你制定标准.那么你肯定采用你偏向的算法..但那一天这个标准不要你来维护了.换人了.别人觉得不好,于是又可以把算法替换他偏向的..
同样的道理...多的我也不说了...对于这个问题的理解,我只能理解成这样.我觉得我自己能把自己糊弄过去就行了.....
amos1989 请看:
http://blog.csdn.net/ZangXT/archive/2009/08/05/4410246.aspx