论坛首页 Java企业应用论坛

Java 是传值还是传引用?关于String的疑惑

浏览 50196 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2005-05-12  
记得以前看书,里面说,"Java 是传值还是传引用,问题主要出在对象的传递上,因为 Java 中简单类型没有引用。"看一下下面的例子:
public class Pass {
String a="123";

public static void test(Pass passA) {
passA.a="abc";
}
public static void main(String[] args) {
Pass passB=new Pass();
passB.a= "123";
System.out.println(passB.a);
test(passB);
System.out.println(passB.a);
}
}
结果是:
123
abc
从这个结果来看是通过引用传递的.String不是简单类型,那么是不是也是通过引用来传递呢?看下面这个例子:
public class Pass {
public static void test(String str) {
str = "World";
}
public static void main(String[] args) {
String string = "Hello";
System.out.println(string);
test(string);
System.out.println(string);
}
}
结果是:
Hello
Hello
第三个例子:
public class Pass {
public static void test(StringBuffer str) {
str.append("World");
}
public static void main(String[] args) {
StringBuffer string = new StringBuffer("Hello");
System.out.println(string);
test(string);
System.out.println(string);
}
}
结果:
Hello
HelloWorld
这我就不太明白了,既然String不是简单类型,那么它应该和对象是一样通过引用来传递的,可是结果却相反.而StringBuffer却是通过引用来传递的?
这到底是为什么?哪位帮忙解释一下.
   发表时间:2005-05-12  
原来是学C++的么?
不要直接用书面上的引用的概念来套
Java中所有的变量都相当于C++中的基本类型变量(如int变量)以及指针变量
对于原生类型,就是传值了,没有什么可说的
对于你说的String以及StringBuffer,这两个都是类的变量就相当于指针了
在C/C++中
void fun(char * string);{
  string="changed";
}
void main(void);{
  char * string="some text";
  fun(string);;
  //string指向什么?
}

至于StringBuffer则相当于
void fun(char * string);{
    string[2]='c';
}
void main(void);{
  char * string="some text";
  fun(string);;
  //string变了没?
}

Java中的“引用”是指非原生类型的变量的保存的是对一个堆上对象的引用。
Java任何时候都是传的,只不过该的语义有所不同罢了
0 请登录后投票
   发表时间:2005-05-12  
莫名其妙。现在的书 和 资料 怎么都是这样故意误导。在一些名词说法上绕圈子,而不从基本原理进行阐述。
“传值和传引用”这个问题,我已经看到在多个地方,提出过多次了。这个问题的出现频率这么高,不能怪读者,主要是“概念制造者”的错。

对于这个问题,如果学过汇编,那么就很容易从堆栈内存结构上理解。
http://dev.csdn.net/article/17/17286.shtm

所有的参数传递都是 传值,从来没有 传引用 这个事实。
所有的参数传递都会在 程序运行栈上 新分配一个 值 的复制品.

楼主的第一段代码。
public static void test(Pass passA); { 
passA.a="abc"; 
} 


这个传的 PassA 的 地址值。这个 地址值 被复制了一份。
不信,你写:
public static void test(Pass passA); { 
passA = null;
} 


看看, 对passA有什么影响?
毫无作用。函数调用出来后,passA还是原来的值,不会变成Null.

但是,你的代码对 passA进行了操作  passA.a ,改变了passA的成员变量。
这个成员变量是一个真实指向String 的 地址,当然能够被改变。
这就是操作 (.)  和 赋值 (=) 的区别。
这是对 成员变量 a 的 赋值。真正改变了成员变量 a 的值。

注意,这里传递的参数是 passA, 而不是 a.
所以,passA 被复制了一份。passA 的这个副本的 a 变量还 指向 原来的 passA 的 a 变量。

楼主后面的代码,
public static void test(String str); { 
str = "World"; 
} 


只有对参数的 赋值,没有对参数的操作,当然不会产生影响。

引用

public static void test(StringBuffer str) {
str.append("World");
}


对参数进行了操作,当然会产生影响。


---
另:
同意“厌倦发呆”的意见。
和我说的一个意思,只是表述重点有些区别。

---
注:
传引用,  只有一种语法现象.
就是 C++的一种语法
void function(int & a){
   a = 1;
}

这个实际上编译为
void function(int * a){
   *a = 1;
}

还是传的 地址值。
0 请登录后投票
   发表时间:2005-05-12  
传引用是没有错的,
public static void test(String str); { 
str = "World"; 
} 

这里的str = "World" 的语义应该是新new String("world")对象,然后把str指向这个堆里面新增的"world"对象,已经不是传进来的"hello"引用了。
	public static void test(String str); { 
	String _str = str;
	str = "world";
	System.out.println(_str);;
	System.out.println(str);;
	} 
可以验证
0 请登录后投票
   发表时间:2005-05-12  
neooen 写道
传引用是没有错的,
public static void test(String str); { 
str = "World"; 
} 

这里的str = "World" 的语义应该是新new String("world")对象,然后把str指向这个堆里面新增的"world"对象,已经不是传进来的"hello"引用了。
	public static void test(String str); { 
	String _str = str;
	str = "world";
	System.out.println(_str);;
	System.out.println(str);;
	} 
可以验证

老兄你的引用观念跟我们差不过,但是不是楼主所理解的那种
C++的引用概念表现上可不是老兄说的这样亚
0 请登录后投票
   发表时间:2005-05-12  
neooen 写道
传引用是没有错的,
public static void test(String str); { 
str = "World"; 
} 

这里的str = "World" 的语义应该是新new String("world")对象,然后把str指向这个堆里面新增的"world"对象,已经不是传进来的"hello"引用了。
	public static void test(String str); { 
	String _str = str;
	str = "world";
	System.out.println(_str);;
	System.out.println(str);;
	} 
可以验证


这个函数调用完了,出来之后呢?
str 是 “hello”, 还是 “world” ?



string str = "hello";
test( str );;

// what is str now?
print(str);;



这里的关键是,传递的参数的作用范围。
传递的参数“值” 会在 函数当前运行栈上 复制一份。所有的 操作和赋值 都是对那个 参数“值”副本 进行的。操作能够 改变成员变量,因为参数“值”副本 是一个 地址,能够正确指向成员变量的位置。而赋值 则根本没用,因为只是改变了当前函数栈内 参数“值”副本 的内容,而没有改变上一层函数栈内的 对应“值”。
0 请登录后投票
   发表时间:2005-05-12  
j0hnny 写道
谢谢各位高人.我没有学过c++,只是偶然碰到这个问题.
我刚才问了一下我老师,他说这个问题不是值传递和引用传递的问题,而是因为String是不可以改的,而BufferString可以改.
我查了一下API,里面这样定义String:
public final class String
Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings. Because String objects are immutable they can be shared.
对于StringBuffer的说明:
A string buffer implements a mutable sequence of characters. A string buffer is like a String, but can be modified.
应该可以作为正解吧?
我觉得所说的非原生类型的变量还是通过引用来传递的吧?
我是初学者,理解不对的地方请大家原谅,这里高手太多了.


你试试看这段代码。
public class Pass { 
public static void test(StringBuffer str); { 
str = new StringBuffer("World");;  //  = 赋值,而不是 append 操作
} 

public static void main(String[] args); { 
StringBuffer string = new StringBuffer("Hello");; 
System.out.println(string);; 
test(string);; 
System.out.println(string);;  // what is it now ?
} 
} 


看看 string buffer 的值 会不会变?
0 请登录后投票
   发表时间:2005-05-12  
j0hnny 写道
谢谢各位高人.我没有学过c++,只是偶然碰到这个问题.
我刚才问了一下我老师,他说这个问题不是值传递和引用传递的问题,而是因为String是不可以改的,而BufferString可以改.
我查了一下API,里面这样定义String:
public final class String
Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings. Because String objects are immutable they can be shared.
对于StringBuffer的说明:
A string buffer implements a mutable sequence of characters. A string buffer is like a String, but can be modified.
应该可以作为正解吧?
我觉得所说的非原生类型的变量还是通过引用来传递的吧?
我是初学者,理解不对的地方请大家原谅,这里高手太多了.

kao,这家伙说话不厚道,你问的是传参的问题,不过这个问题不涉及到string能不能改啊,就是赋值的语义问题啊。stringbuffer是线程安全的可以修改,string线程不安全好象,所以讲their values cannot be changed 。出来混讲究厚道两字,最讨厌看到高手两字,大家重在交流嘛
0 请登录后投票
   发表时间:2005-05-12  
kao 都是老问题了 前面很多的帖子都讨论过的,仔细看的话就会楼主就好明白啦

http://forum.iteye.com/viewtopic.php?t=11649

http://forum.iteye.com/viewtopic.php?t=12447
0 请登录后投票
   发表时间:2005-05-12  
neooen 写道
j0hnny 写道
谢谢各位高人.我没有学过c++,只是偶然碰到这个问题.
我刚才问了一下我老师,他说这个问题不是值传递和引用传递的问题,而是因为String是不可以改的,而BufferString可以改.
我查了一下API,里面这样定义String:
public final class String
Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings. Because String objects are immutable they can be shared.
对于StringBuffer的说明:
A string buffer implements a mutable sequence of characters. A string buffer is like a String, but can be modified.
应该可以作为正解吧?
我觉得所说的非原生类型的变量还是通过引用来传递的吧?
我是初学者,理解不对的地方请大家原谅,这里高手太多了.

kao,这家伙说话不厚道,你问的是传参的问题,不过这个问题不涉及到string能不能改啊,就是赋值的语义问题啊。stringbuffer是线程安全的可以修改,string线程不安全好象,所以讲their values cannot be changed 。出来混讲究厚道两字,最讨厌看到高手两字,大家重在交流嘛



不是我不厚道,我确实问的是传参的问题,没有考虑到String是final的,当时没有想那么多,只是想弄明白是怎么回事。并不是通过这个混淆大家的思路,这个我也是后来才知道的。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics