2012年3月18日星期日

引用(别名)是什么?

由一个简单的JAVA问题引发了一场热情洋溢的群众喜闻乐见的讨论,同时扯到C++上。。。
先上代码:


public class test {
public static void main(String[] args){
int a = 4;
int b = a;
String s1 = "abc";
String s2 = s1;
String s3 = "def";
String s4 = "def";
System.out.println(a == b);     // 1
System.out.println(s1 == s2);   // 2
System.out.println(s3 == s4);   // 3
s3 = "abc";
System.out.println(s1 == s3);   // 4
s2 = "abcdef".substring(3,6);
System.out.print(s2 + "\t" + s4 + "\t");  
System.out.println(s2 == s4);   // 5
System.out.println(s2.equals(s4));  // 6
s3 = args[0];
System.out.print(s1 + "\t" + s3 + "\t");
System.out.println(s1 == s3);  // 7
System.out.println(s1.equals(s3));   // 8
  a--;
  System.out.println(a + " " + b);     // 9
}
}



output example:

上面的结果能说明一些问题:
注释3处表示,s3,s4指向同一个内存地址,也就是说,“abc”这个字符串在编译时经过优化存放在全局数据区,并不会产生两个相同的string。

注释4处表示,s3 = "abc"这句是将s3指向"abc"这个字符串对象,而并不是修改s3原先指向的"def"处的内容。这证实了书上说的“string对象是不可变的”。

注释5、6处证明了 == 比较的是两个引用所指向对象的物理地址,而不是对象的值。用equals()比较值的结果是true,用 == 比较内存地址的结果是false,因为s2是从另一个字符串的返回的string子串,虽然内容和"abc"一样,但物理地址是不同的。
注释7、8处同理。从args传入参数。

(后来加上去的)注释9处,是验证b是否为a的引用。结果显示为 "3 4",说明a,b是独立的。同样的句式,用在string上和用在int上效果完全不一样,何解?因为int是基本类型,而String是一个类。
确实,很多时候我们潜意识里以为String和int都是基本类型,其实不然。

说到底,s2是s1的一个浅copy,不是深copy。
这里引用一段师兄的话
关于别名,其实就是编译器在编译时帮某个变相定义的另外一个名字而已,你就把引用当作在编译时编译器帮你默认写了个typedef。它其实不会产生额外内存开销(至少在C/C++里面是这样),只是编译的trick,按照我的理解,它应该仅存在于编译后产生的符号表里面,所以本身也没有地址。
 也就是说,一般情况下,引用(别名)本身是不占空间的,这和C++的定义是一致的。符号表是关键....

附一个stackoverflow上关于引用的解释: http://stackoverflow.com/questions/1179937/how-does-a-c-reference-look-memory-wise

再次清楚的意识到自己的基础知识该有多差。。。细节决定成败啊!
还是要潜心钻研学术,低调求发展。。。
“勿在浮沙筑高台”


没有评论:

发表评论