对于字符串对象来说,虽然在参数传递的时候也是引用传递,但是java虚拟机在函数内部对字符串对象进行了特殊处理--视String对象为常量(final) 所以对传进来的引用地址所引用的string对象比能直接进行修改,而是产生一个副本对其进行操作,对其进行的操作不会影响原来的值。 下面我们看一例子(sun认证试题)来证明这一点: 1. public class X { 2. public static void main (String[]args) { 3. string s = new string (“Hello”); 4. modify(s); 5. System.out.printIn(s); 6. } 7. 8. public static void modify (String s) { 9. s += “world!”; 10. } 11. } 你说它会打印出什么结果?是Helloworld?可能大部分人会说是这个答案吧,哈哈结果却是Hello,为什么呢?再仔细分析一下上边所说的吧-----“视String对象为常量(final)” 这是问题的关键!在modify()方法中传进了string对象,虽然是引用传递,上边我们说了视String对象为常量(final),它不会修改原来地址所引用的值,而是生成一个副本对其进行操作,所以打印结果应该为Hello!下面再讲一讲java中对常量(final)是怎样处理优化的,以便更深入的理解上面的问题: java中的final变量,java编译器是进行了优化的。每个使用了final修饰的变量的地方都不会通过连接而进行访问。比如说Test类中使用了Data类中一个final的int数字fNumber=77,这时候,java编译器会将77这个常数编译到Test类的指令码或者常量池中。这样,每次Test类用到fNumber的时候,不会通过引用连接到Data类中进行读取,而是直接使 我们再来举个例子说明这一点: public class TestFinal(){ public static void main(string s[]){ System.out.println(FinalData.date); } public class FinalData(){ public static final data=8; } } 运行上面的TestFinal类结果为:8 但是你把FinalData类中的data=88,编译后再运行TestFinal类结果还是8,这是因为编译器把data的副本保存TestFinal类中,所以在重新编译TestFinal类的前,TestFinal类一直把data认为是8而不是88,是不是证明了上面所讲述的每个使用了final修饰的变量的地方都不会通过连接而进行访问!结合这个例子,再深入的想一想第一个问题是不是就理解的更加清晰了
{
StringBuffer tempStr = new StringBuffer(); //构造一个tempStr的StringBuffer对象 System.out.println("first : " + str);//输出str,没有问题,肯定是hello
str = str.append(" world");//在hello后面连接" world",并重新赋值给str,所以str现在是"hello world"
System.out.println("second: " + str); //输出"hello world"
str = tempStr; //将str指向tempStr,注意这里的str直接赋值和前面append的区别,append
//能改变这个str对象,而str这个形式参数只是指向了tempStr空间,一旦方法结束,str还是原来的str,
//也就是append之后的那个str "hello world"
System.out.println("third : " + str);
}于String的对比代码,请看:
public static void test(String str)
{
String tempStr = ""; System.out.println("first : " + str);
str = str +" world";
System.out.println("second: " + str);
str = tempStr;
System.out.println("third : " + str);
}
public static void main(String args[]) {
String str1 = "hello";
test(str1);
System.out.println("main : " + str1); }
上面的代码输出和你的代码不一样 因为String是不可变的(immutable),而StringBuffer是可变的(mutable)。再来看下面这段代码:
public static void test(StringBuffer str)
{
StringBuffer tempStr = new StringBuffer(); System.out.println("first : " + str);
str.append(" world"); //把str = str.append(" world")改成这样 对结果没有任何影响
//更说明了append方法对于StringBuffer对象的改变 (具体参见源码),而不在于你赋值与否;也说明了
//str只是个形式参数
System.out.println("second: " + str);
str = tempStr;
System.out.println("third : " + str);
}
http://zhidao.baidu.com/question/5912766.html
看看这个对你有帮助
public static void main(String[] args)
{
StringBuffer str1 = new StringBuffer("hello");
test(str1);
System.out.println("main : " + str1);
}
public static void test(StringBuffer str)
{
StringBuffer tempStr = new StringBuffer(); System.out.println("first : " + str);
str = str.append(" world");
System.out.println("second: " + str);
str = tempStr;
System.out.println("third : " + str);
}请记住Java中函数永远是值传递的。
StringBuffer str1 = new StringBuffer("hello");
在堆内存声明了一个StringBuffer实例,传入参数“hello”。test()方法调用时,str1在栈内存中的对象引用被赋值给局部变量str,此时str和str1指向堆内存中的同一个StringBuffer对象。
接着输出str(同str1),结果是:hello;
append()将world追加到str(str1)变量所指向的StringBuffer中。注意由于str1和str指向同一个Stringbuffer对象,所以str1的值被改变,结果是“hello world”。
System.out.println("second: " + str)的打印结果当然是:hello world。
str = tempStr;这句将使str变量指向tempStr在堆内存中申请的内容为空字符串的StringBuffer对象,其实就是一个tempstr的别名。此时System.out.println("third : " + str);当然是空了。
退出test()方法后,由于str1的内容已经改变为:"hello world"
所以main方法中的System.out.println("third : " + str);打印输出为:hello world。
Java中函数永远是值传递的。如何理解? 传简单类型(int,short,Integer)的时候,就是值的拷贝!
传引用类型(StringBuffer.....)的时候,传的就是引用的拷贝,这里说的值就是指"对象的引用"吗?
而不是对象本身???????????????????????????
str.append 就是 str1.append 所以 second: hello world (第二个 sysout)
str = tempStr 就是把 str指向tempStr所指向的地址。而是str1所指向的地址没有变(不要把参数str当做str1) third : (第三个 sysout)
(第四个 sysout)因为str1 所指向的地址一直没有变,他只append了world 所以 main : hello world
对象和数组就属于引用类型。
c++里才有
是你把它特殊化了吧?你去看看这篇blog:对于String的认识
2. public static void main (String[]args) {
3. string s = new string (“Hello”);
4. modify(s);
5. System.out.printIn(s);
6. }
7.
8. public static void modify (String s) {
9. s += “world!”;
10. }
11. } 你说它会打印出什么结果?是Helloworld?可能大部分人会说是这个答案吧,哈哈结果却是Hello,为什么呢?再仔细分析一下上边所说的吧-----“视String对象为常量(final)” 这是问题的关键!在modify()方法中传进了string对象,虽然是引用传递,上边我们说了视String对象为常量(final),它不会修改原来地址所引用的值,而是生成一个副本对其进行操作,所以打印结果应该为Hello!下面再讲一讲java中对常量(final)是怎样处理优化的,以便更深入的理解上面的问题: java中的final变量,java编译器是进行了优化的。每个使用了final修饰的变量的地方都不会通过连接而进行访问。比如说Test类中使用了Data类中一个final的int数字fNumber=77,这时候,java编译器会将77这个常数编译到Test类的指令码或者常量池中。这样,每次Test类用到fNumber的时候,不会通过引用连接到Data类中进行读取,而是直接使 我们再来举个例子说明这一点: public class TestFinal(){ public static void main(string s[]){ System.out.println(FinalData.date); } public class FinalData(){ public static final data=8; } } 运行上面的TestFinal类结果为:8 但是你把FinalData类中的data=88,编译后再运行TestFinal类结果还是8,这是因为编译器把data的副本保存TestFinal类中,所以在重新编译TestFinal类的前,TestFinal类一直把data认为是8而不是88,是不是证明了上面所讲述的每个使用了final修饰的变量的地方都不会通过连接而进行访问!结合这个例子,再深入的想一想第一个问题是不是就理解的更加清晰了
你去看下我的blog和里面链接的几篇文章 然后看看别人的回复 就知道了 我在二楼也说了 String是immutable的 然后我2#里的几个代码的逻辑关系不知道你看明白没
然后,你自己又弄了一个新包裹, 在里面塞了一只烟灰缸。问题: 原来的包裹有什么东东? 不知道你是否明白了这个问题的答案? 请结合我上面的答复再看看,
表述不好,见谅!
public static void main(String[] args)
{
StringBuffer str1 = new StringBuffer("hello");
test(str1);
System.out.println("main : " + str1);
}
public static void test(StringBuffer str)
{
StringBuffer tempStr = new StringBuffer(); System.out.println("first : " + str);//此时str是main方法中的str1的引用
str = str.append(" world");
System.out.println("second: " + str);
str = tempStr; //此时str的引用改变了,改为对tempStr的引用,但main方法中的str1的内容没有改变哦。
System.out.println("third : " + str);
}
C++/C 也一样, 都是值传递,就是被一群傻13 搞得那么复杂的规则!Thinking in java, 里面已经明确的指出, 不要区分传啥, 最终是传值的
str = tempStr; //将str指向tempStr,注意这里的str直接赋值和前面append的区别,append
//能改变这个str对象,而str这个形式参数只是指向了tempStr空间,一旦方法结束,str还是原来的str,
//也就是append之后的那个str "hello world" 这个怎么可能呢??
str之前指向的是传入的参数str1所指向的内存空间,所以之前的操作会影响外部的变量str1的值的
而经过这条语句后,str已经指向了新new出来的内存空间,也就是tempStr所指向的内存空间
执行完了,str也不会再重新指向原有的内存空间呀,
System.out.println("third : " + str);
这条执行后,就会等待时机进行垃圾回收了呀~~~~
之所以最后输出main : hello world 只是由于之前的影响造成的呀
public static void test(String str)
{
String tempStr = ""; System.out.println("first : " + str);
str = str +" world";//这里产生了新对象
System.out.println("second: " + str);
str = tempStr;
System.out.println("third : " + str);
}
public static void main(String args[]) {
String str1 = "hello";
test(str1);
System.out.println("main : " + str1); }
其实10楼说的也没错
public static void test(String str) 这里的str是一个新的引用 即形参。它和str1 同时指向了"hello".
只不过String是个特别的,确如你所说它是不可变的。
所以
str = str +" world"; 又生成了一个新的String "hello world",然后str重新指向hello world"。而这个时候str1仍然是指向"helle"的。故最后在main中输出时 :
first : hello
second: hello world
third :
main : hello。另外谈一下我自己对java值传递的理解。
如:public static void test(String str)
这里传过来的str 明明就是传的"hello"这个字符串的引用,为什么说是值传递呢??因为这里的值是指引用的值!我们知道引用其实也是一个对象,而这个对象的内容包含了它所引用对象的地址罢了。所谓值传递应该理解为值的复制。所以这里说的值传递是指引用的值传递。
归纳下来 ,对于基本类型 int long 等:值传递传的就是这个对象本身。即传递时将这个基本类型拷贝一份,传的是副本,而本体不会发生任何改变。public static void main(String[] args)
{
int i = 3;
test(i);
System.out.println("main:"+i);
}
public static void test(int i)
{
i=i+100;
System.out.println("first : " + i);
}
结果
first : 103
main:3
对于对象类型,String StringBuffer都属于对象类型。值传递时传的是对象引用的值,即将对像的引用拷贝一份,将副本传给方法。test方法中的str 与str1为两个完全不一样的东东。(即便我们有时候把两个参数写为一样也不影响,因为一个是局部变量)。他们同时指向了"hello"对象。对他们的操作实质都是通过地址找到"hello"对象进行操作。但是当:str = tempStr;这个操作并不能对str指向的对象进行操作。而是引用的赋值运算,即将tempStr的内容(引用对象的地址)赋给了str.
我说明白了么?
我想说的观点s=s+"a";永远都是新生成了对象。个人猜测,欢迎拍砖
至于s=s+"a";永远都是新生成了对象。如果能给于确切答案的话,还望不吝赐教。
String str2 = "a" + "bc";
String str3 = str2 + "";//你去判断str1,str2,str3是否 “==”
抱歉抱歉,我说错了。自己实践了下爆汗!
看代码
public static void main(String[] args)
{
String s1 = "test";
String s2 = "test";
String s3 = "te"+"st";
String s4 = new String("test");
System.out.println("s1=s2?:"+(s1==s2));
System.out.println("s1=s3?:"+(s1==s3));
System.out.println("s1=s4?:"+(s1==s4));
}结果:
s1=s2?:true
s1=s3?:true
s1=s4?:false结论:
对象String s = "test";这样的应该是从String池里取得。
对于String s = "te"+"st";这样的 ,如果池子里有肯定也是从池子里取。
而对于 new String("test").则永远是新生成对象。
我居然忘了老师说的 new 永远是 new! 哎 抱歉啊!
至于对sting 池 我刚刚看来一些资料。因为之前也对这个有所疑惑。这个池子里到底会放哪些String对象呢。原来啊 ,String 池应该叫常量池,它里面不管有String对象,还有一些基本数据类型。常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。
用new String() 创建的字符串不是常量,不能在编译期就确定,所以new String() 创建的字符串不放入常量池中,它们有自己的地址空间。
{
String s1 = "test";
String s2 = "test";
String s3 = "te";
String s4 = "st";
String s5 = s3+"st";
String s6 = s3+s4;
String s7 = "te"+"st";
String s8 = new String("test");
System.out.println("s1=s2?:"+(s1==s2));
System.out.println("s1=s5?:"+(s1==s5));
System.out.println("s1=s6?:"+(s1==s6));
System.out.println("s1=s7?:"+(s1==s7));
System.out.println("s1=s8?:"+(s1==s8));
}
结果
s1=s2?:true
s1=s5?:false
s1=s6?:false
s1=s7?:true
s1=s8?:false
有什么想法呢??
我的那个blog里有啊 因为s是变量 和s = "ab" + "c"不一样 一个是编译时确定 一个是运行时确定 正解啊!佩服!
{
StringBuffer str1 = new StringBuffer("hello");//声明一个引用str1,创建一个StringBuffer对象(叫对象A吧),里面放的是"hello"这个字符串.
test(str1); //调用test方法,详细看下面的注释.
System.out.println("main : " + str1);//str1所指向的对象A在test方法中被追加了" world"字符串,所以打印结果为"main : hello world".
}
public static void test(StringBuffer str)//在test方法参数栈(姑且这么叫吧)上声明一个引用str,指向上面存有"hello"字符串的StringBuffer对象(对象A).
{
StringBuffer tempStr = new StringBuffer(); //声明一个引用tempStr,创建一个StringBuffer对象(叫对象B吧),里面放的是空字符串. System.out.println("first : " + str);//由于指向的的StringBuffer对象(对象A)存的是"hello",所以打印"firs : hello"
str = str.append(" world");//调用append方法,对象A追加字符串" world",现在对象A的内容为"hello world".
System.out.println("second: " + str);//打印对象A,结果"second: hello world".
str = tempStr;//引用str指向引用tempStr所指向的对象B,此时str所指向的对象内容为空字符串.
System.out.println("third : " + str);//因此打印结果"third : "
}
这个家伙很嚣张,丢我个板砖,我的这句话是从《JAVA大学教程》第四版看到的,其中基本类型有int,char,boolean,String ,对象类型有Integer,StringBuffer。
对于基本数据类型,如int,float,double等为值传递,
而针对对象,都是引用传递,
{
StringBuffer str1 = new StringBuffer("hello");
test(str1);
System.out.println("main : " + str1);
}
public static void test(StringBuffer str)
{
StringBuffer tempStr = new StringBuffer(); System.out.println("first : " + str);
str = str.append(" world");
System.out.println("second: " + str);
str = tempStr; A
System.out.println("third : " + str);
}
(A处)通过 str = tempStr (把 tempStr 的引用传给了 str,导致了 str
指向了 对象 tempStr ,因此 third 的值为:null(空)
Java 中的函数 传过的参数 为: 单项值传递
即 把 str1 传给 函数 test ,test 可以用 str1 进行操作
而 test 中对 str1 的改变 ,不会传递到 main 函数中
{
StringBuffer str1 = new StringBuffer("hello"); //str1->"hello"
test(str1);
System.out.println("main : " + str1);
}
public static void test(StringBuffer str)
{
/*注意这里产生了一个新的指针和
*str1指向同一个字符串str->"hello"
*/
StringBuffer tempStr = new StringBuffer(); //一个新的对象 System.out.println("first : " + str);
str = str.append(" world"); //这里"hello"变成了"hello world"会影响到str和str1
System.out.println("second: " + str);
str = tempStr; //这里把str指向了一个新对象,主意str1的指向并没有发生变化
//到此为止str指向tempStr 而str1指向"hello world" 两个指针分别指向了不同对象
System.out.println("third : " + str);
}