做个string的测试咯。如下:


/**

 * Created by lxk on 2016/8/19 
 */ 
public class Test { 
    public static void main(String[] args) { 
        String a = "abc"; 
        String b = "abc"; 
        String c = new String("abc"); 
        String d = "ab" + "c"; 
        System.out.println("a == b" + a == b); //false  
        System.out.println("a == c" + a == c); //false  
        System.out.println("a == d" + a == d); //false  
        System.out.println("b == c" + b == c); //false  
        System.out.println("b == d" + b == d); //false  
        System.out.println("c == d" + c == d); //false  
    } 
}

代码中警告的原因:
(1)
String c = new String("abc");
可以直接写成如下,上面那么写,就有些啰嗦,脱裤子放屁。哎呀,好不优雅的比喻。咦。。。
String c = "abc";
(2)
意思就是字符串比较不能用  == ,要用equals()方法

注意:

上面的代码和测试结果,都是完全错误的,一失足成千古恨。

要是你一眼就能看到我哪里错了,说明你很还是很牛x的。没一眼看出来,也不要紧。

下面再进行正确的测试。并说明上面错误的地方。

下面是正确的测试代码和测试结果。



测试代码:

package com.lxk.test; 
 
/** 
 * 字符串测试Class 
 * <p> 
 * Created by lxk on 2017/2/8 
 */ 
public class StringTest { 
    public static void main(String[] args) { 
        testStringPool(); 
    } 
 
    /** 
     * 测试字符串常量池的问题 
     */ 
    private static void testStringPool() { 
        String a = "abc";//字面量形式 
        String b = "abc";//字面量形式 
        String c = new String("abc");//使用new标准的构造对象 
        /* 
            注意:这个虽然看起来似乎要在常量池新建三个字符串对象:ab,c,和拼接生成的abc 
            但是结果是内存中仅有生成的,前面的两个算是过程变量。这反编译得出来的结论,我没测试哟! 
            这样做实际上是一种优化,避免了创建多余的字符串对象,也没有发生字符串拼接问题 
         */ 
        String d = "ab" + "c";//字面量形式 
        System.out.println("a == b " + (a == b));//true 
        System.out.println("a == c " + (a == c));//false 
        System.out.println("a == d " + (a == d));//true 
        System.out.println("b == c " + (b == c));//false 
        System.out.println("b == d " + (b == d));//true 
        System.out.println("c == d " + (c == d));//false 
        System.out.println("-----------------"); 
        System.out.println("abc" == ("ab" + "c"));//true 
        System.out.println("-----------------"); 
        String e = c.intern();//将new出来的字符串对象加入字符串常量池 
        System.out.println(a == e);//true 
    } 
} 


对上面结果的解释说明:
首先上面的比较过程是直接拿 == 来比较的,没有用equal方法,那么用 == 来比较的话,比较的是地址。并不是值
可以看到,a,b,d,三个字符串直接用 == 比较,比较出来的结果都是true。是相等的。
意思就是说这三个变量在空间上都是指向同一个内存地址。这就涉及到一个字符串常量池的问题啦。
但是和c比较的时候,却不相等,因为,c是new出来的,记得当时学习的时候,new都是在堆内存里面的,新开辟的空间。
所以,地址肯定就不相同啦。


对上面的错误测试做解释:

我之所以错误了 ,是因为,我在打印结果的时候,没有注意到运算符的优先级问题。

我也没有看到我的打印结果和自己期望的结果是不同的,期望结果起码应该是:a == b false,这个形式的,但是我却没有注意到我当时代码的测试结果仅仅只有:false。

知道问题所在的话,就知道上面的代码怎么错了:前面的字符先是拼接起来,然后再和后面的变量字符串对比,结果当然是false啦。

所以,之前的测试结果一直都是false。

尴尬啦。


之所以有这篇文章,估计当时,看到这个问题,在网上搜索,答案五花八门。所以,我就自己亲自动手,搞了个测试。万万没想到。我还给搞错了。多谢下面那位仁兄的评论,我又回头 再看这个问题,就发现问题所在啦。


关于常量池的简单解释:(后面追加的内容)

Java中字符串对象创建有两种形式。
一种为字面量形式,如String str = "droid";,
另一种就是使用new这种标准的构造对象的方法,如String str = new String("droid");
这两种方式我们在代码编写时都经常使用,尤其是字面量的方式。然而这两种实现其实存在着一些性能和内存占用的差别。
这一切都是源于JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池。
工作原理
当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查。
如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回。
否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。


经过上面的这番解释,可以知道,新添加的那行代码的运行结果应该是:true。


以下是更新于(2017/06/23


就算你仔细看了上面的测试代码,要是再这么一下,稍微加个final,修饰一下字符串。那么结果又有点不同啦。

具体运行结果,如下图。


对上述运行结果的解释:

这里面就是final变量和普通变量的区别了.
当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。
也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行时确定。
这种和C语言中的宏替换有点像。
因此在上面的一段代码中,由于变量bb被final修饰,因此会被当做编译器常量,所以在使用到bb的地方会直接将变量bb替换为它的值。
而对于变量dd的访问却需要在运行时通过链接来进行。
想必其中的区别大家应该明白了.
不过要注意,只有在编译期间能确切知道final变量值的情况下.编译器才会进行这样的优化.


为什么有这次更新

因为在看到final的用法的时候,又出现了字符串比较,又涉及到了字符串常量池的问题,我就干脆放一起好啦。




评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!