Java中的String及传参的一些浅见

//很明显,生成了一个对象,是编译期生成的。

String str1 = “abc”;  //这个呢?答案是并没有生成对象,只是把一个引用指向了”abc”对象,换言之,strstr1指向了同个对象。大家可以用(str == str1)来判断它们是不是指向同个对象。

这样是不是说明当修改str1时,str也会跟着修改呢?答案是否定的。比如说,

str1 = “def”;   大家会发现,str的内容并没有变成def,还是abc。那这里面究竟发生了什么事?

当运行代码时,编译器会在常量池里寻找有没有一个值为”abc”的字符串对象,哦,没有,所以它创建了一个这样的对象。当运行代码时,编译器在常量池里找到了一个这样的对象,所以就把str1也指向了它。当运行代码时,编译器又在常量池里寻找值为”def”的对象,结果发现没有,所以就再创建了一个字符串对象。因此,总结一下,上面三句代码,总共创建了两个对象。

再看下面的代码: String tmp = “a” + “bc”;  //请问,这里有创建新对象吗?答案是没有的。因为括号内文本的方式都是在编译期就解决掉的。所以当运行代码时,编译器在常量池里寻找有没有一个值为”abc”的对象,结果是找到了,所以就把tmp指向它。由于在栈里的速度非常快,像刚刚描述的过程,事实上,只是移动一下指针,因此,效率会比用new在堆里生成对象高很多。强调一句,用new在堆里生成对象,不管内容是不是一样,都会生成相应的实例。比如说String tmp1 = new String(“chop”); String tmp2 = new String(“chop”);这里就铁定地生成了两个对象。虽然它们的值是一样的,但却是两个指向不同地方的引用。

 

关于java传值问题

首先,在java之父所写的书里就有一句这样的话:java里只有一种传值方式:值传递。我们不来搞个人崇拜,权威定理。那我们就用代码来说明吧。大家猜测一下代码的输出结果是什么?

public class Test

{

    public void changeStr(String tmp){

        tmp = "你不是人才!";

    }

public static void main(String args[]){

Test obj = new Test();

        String str = "我是人才!";

        obj.changeStr(str);

        System.out.println(str);

    }

}

很遗憾地告诉大家,结果是我是人才!。再联想一下值传递的想法就很清楚了。在main方法那里,生成了一个String对象,值为我是人才。然后有个str引用指向了它。当调用changeStr(str)方法时,就把str引用复制了一份(注意,这里是复制了一份str引用),然后再把它传递给changeStr方法。换言之,现在有两个引用指向了那个对象。在方法内部,把那个复制的引用又指向了另一个对象(其值为你不是人才!)。但原来那个引用所指向的对象还是没变。因此,你再打印str,自然结果还是我是人才!了。

 

关于String的进一步讨论

如果大家对第一部分的讨论还有疑惑,我们可以把第二部分的代码再修改一下的,大家看一下下面的代码输出

public class Test

{

    public String changeStr(String tmp){

        tmp = "我是人才!";

        return tmp;

    }

public static void main(String args[]){

Test obj = new Test();

        String str = "我是人才!";

        String tmp = obj.changeStr(str);

         System.out.println(tmp == str);    //你觉得会输出什么呢?truefalse。在java里,对于类而言,==是用来判断两个引用所指向的对象是不是同个对象的。

        System.out.println(str);

    }

}

运行过代码就会发现,结果是true。也就是说,引用内文本生成的对象是放在常量池的,并且在编译期就已经解决了。

如果我再把changeStr(String tmp)方法改一下,把tmp = “我是人才!”;改成tmp = new String(“我是人才!”);输出结果很明显就是false了。虽然它们的值是一样的,但由于是在运行时在堆里生成的对象,tmpstr所指向的是不同对象的。

总结一下上面所说的,大家主要是要分清楚哪些是编译期就可以确定的,哪些要运行时才能确定,哪些是在栈里的,哪些是在堆里的,这样就会很清晰了。

有高手说,像这样的问题,最好是去看《深入java虚拟机》或是直接反汇编代码来理解。没办法,本人水平菜,那样的东西暂时还看不懂,只能先这样理解了。有不正确的地方还请斧正!

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值