zoukankan      html  css  js  c++  java
  • Java温故知新 字符串


    一、常量池

    对于源程序中出现的字符串常量,当程序运行时,会统一保存到一个常量池中进行缓存。
    对引用这些缓存在常量池中的字符串的变量进行比较,用==也会得到正确的结果。

    但在运行时,对字符串的各种操作如+、substring等等,都是会产生新的字符串对象的。
    但是强大的编译器会对字符串常量的拼接进行优化,诸如s3 = "hell" + "o"时,s3仍然会
    指向常量池中的字符串。但对于变量的运算,总不能要求虚拟机执行诸如s1 + s2时还要
    判断结果是否已在常量池中了吧。因此,要用equals而非==去判断两个字符串是否相等。
    	public static void main(String[] args) {
    
    		// String constants are put in constant pool.
    		String s1 = "hello";
    		String s2 = "hello";
    		String s3 = "hell" + "o";
    		System.out.println(s1 == s2);
    		System.out.println(s1 == s3);
    		
    		// Operation like +,substring on string create new one. 
    		String s4 = "hell";
    		String s5 = s4 + "o";
    		System.out.println(s1 == s5);
    		System.out.println(s1.equals(s5));
    		
    		// substring has special handle on substring(0)
    		String s6 = s1.substring(0);
    		System.out.println(s1 == s6);
    	}
    

    测试代码s1、s2、s3的字节码:

       0:   ldc     #16; //String hello
       2:   astore_1
       3:   ldc     #16; //String hello
       5:   astore_2
       6:   ldc     #16; //String hello
       8:   astore_3

    测试代码s4、s5的字节码:
       
       41:  ldc     #30; //String hell
       43:  astore  4
       45:  new     #32; //class java/lang/StringBuilder
       48:  dup
       49:  aload   4
       51:  invokestatic    #34; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
       54:  invokespecial   #40; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
       57:  ldc               #43; //String o
       59:  invokevirtual   #45; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
       62:  invokevirtual   #49; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;


    注意一点是substring方法,substring(0,3)是得到从字符0到2的字符串。这样设计的原因
    也许是这样容易计算子串的长度,3-0=3。同时substring对于特殊参数有特别的优化处理:
        public String substring(int beginIndex, int endIndex) {
            if (beginIndex < 0) {
                throw new StringIndexOutOfBoundsException(beginIndex);
            }
            if (endIndex > count) {
                throw new StringIndexOutOfBoundsException(endIndex);
            }
            if (beginIndex > endIndex) {
                throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
            }
            return ((beginIndex == 0) && (endIndex == count)) ? this :
                new String(offset + beginIndex, endIndex - beginIndex, value);
        }
    

    由此看出,String对象背后并没有什么神奇之处,对字节码有了些了解可以更好的理解它。
    其实常量池中还保存类及其方法的很多信息,如包名、类名、方法签名等等,有兴趣可以
    深入研究。


    二、性能

    另外关于字符串的拼接,从上面的字节码还可以看出一点,就是强大的编译器已经帮我们
    将+自动优化为使用StringBuilder进行拼接,而非每次都产生一个新的String对象。强大的
    编译器啊!

    字符串拼接的性能测试:http://coolshell.cn/articles/2235.html


  • 相关阅读:
    数据库Mysql给用户赋予操作表的权限
    C# log4net日志分等级打日志
    C# 将字符串转为函数名
    C# winform无法拖动控件
    C# 程序获取管理员方法
    C# 生成程序目录避免生成多余的XML和pdb
    C# 快速获取一个月的天数或最后一天
    正则
    C# 根据服务名打开所在文件夹
    330 div+css Experience
  • 原文地址:https://www.cnblogs.com/xiaomaohai/p/6157830.html
Copyright © 2011-2022 走看看