java string 优化_JAVA字符串,以及字符串的优化相关

String类型,是Java对char数组的进一步封装,占8个字节

String类的实现主要由三部分组成:char数组,offset偏移量,String的长度。

String类型有三个基本特点:

1、不可变性

不变性是指String对象一旦生成,则不能再对它进行改变。 在一个对象被多线程共享,而且被频繁的访问时,可以省略同步和锁的时间,从而提高性能。而String的不变性,可泛化为不变模式。

不变性的作用在于当一个对象需要被多线程共享,并且频繁访问时,可以省略同步和锁等待的时间,从而大幅提高系统性能。

2、针对常量池的优化

当两个String对象拥有相同的值时,它们只引用常量池中的同一个拷贝。

例如:

1 String s1 = "123";2 String s2 = "123";3 String s3 = new String("123");4 System.out.println(s1 == s2); //true

5 System.out.println(s1 == s3); //false

6 System.out.println(s1 == s3.intern()); //true

以上代码中,s1和s2引用的是相同的地址,故而第s1==s2是true;

而s3虽然与s1,s2相等,但是s3时通过new String(“123”)创建的,重新开辟了内存空间,因引用的地址不同,

所以第s1==s3是false;intern方法返回的是String对象在常量池中的引用,所以s1 == s3.intern()是true。

3、被final修饰过

作为final类的String对象在系统中不能有任何子类,正是因为这个,才保证了不可变。

如下图,给一个已有字符串"abcd"第二次赋值成"abcedl",不是在原内存地址上修改数据,而是重新指向一个新对象,新地址。

10340747.html

0WwkTfoER7AAAAAASUVORK5CYII=

为什么要被final修饰?

1、不可变性支持线程安全。

在并发场景下,多个线程同时读一个资源,是不会引发竟态条件的。只有对资源做写操作才有危险。不可变对象不能被写,所以线程安全。

2、不可变性支持字符串常量池

这样在大量使用字符串的情况下,可以节省内存空间,提高效率。但之所以能实现这个特性,String的不可变性是最基本的一个必要条件。要是内存里字符串内容能改来改去,这么做就完全没有意义。

1 String one = "someString";2 String two = "someString";

由于内存里面指向的是同一个地址,所以one==two 是true。

10340747.html

B8slpQQ5BFp0AAAAAElFTkSuQmCC

2、字符串操作中的常见优化方法

2.1 split()方法优化

通常情况下,split()方法带给我们很大的方便,但是其性能不是很好。建议结合使用

indexOf()和subString()方法进行自定义拆分,这样性能会有显著的提高。

2.2 String常亮的累加操作优化方法

示例代码:

1 String str = "";2 long strBeginTime =System.currentTimeMillis();3 for (int i = 0; i < 100000; i++) {4 str += "s";5 }6 long strEndTime =System.currentTimeMillis();7 System.out.println("str拼接100000遍s耗时: " + (strEndTime - strBeginTime) + "ms");8

9 StringBuffer str1 = newStringBuffer();10 long str1BeginTime =System.currentTimeMillis();11 for (int i = 0; i < 100000; i++) {12 str1.append("s");13 }14 long str1EndTime =System.currentTimeMillis();15 System.out.println("str1拼接100000遍s耗时: " + (str1EndTime - str1BeginTime) + "ms");16

17 StringBuilder str2 = newStringBuilder();18 long str2BeginTime =System.currentTimeMillis();19 for (int i = 0; i < 100000; i++) {20 str2.append("s");21 }22 long str2EndTime =System.currentTimeMillis();23 System.out.println("str2拼接100000遍s耗时: " + (str2EndTime - str2BeginTime) + "ms");

结果:

str拼接100000遍s耗时: 3465ms

str1拼接100000遍s耗时: 7ms

str2拼接100000遍s耗时: 4ms

所以,使用+号拼接字符串,其效率明显较低,而使用StringBuffer和StringBuilder的

append()方法进行拼接,效率是使用+号拼接方式的百倍甚至千倍,而StringBuffer的效率

比StringBuilder低些,这是由于StringBuffer实现了线程安全,效率较低也是不可避免的。

所以在字符串的累加操作中,建议结合线程问题选择,应避免使用+号拼接字符串。

2.3 StringBuffer和StringBuilder的选择

上例中也使用过StringBuffer和StringBuilder了,两者只有线程安全方面的差别,所以呢,在无需考虑线程安全的情况下,建议使用性能相对较高的StringBuilder类,若系统要求线程安全,就选择StringBuffer类。

2.4 基本数据类型转化为String类型的优化方案

示例代码:

1 Integer num = 0;2 int count = 100000;3 long beginTime =System.currentTimeMillis();4 for (int i = 0; i < count; i++) {5 String s = num + "";6 }7 long endTime =System.currentTimeMillis();8 System.out.println("+号拼接的方式耗时: " + (endTime - beginTime) + "ms");9

10 beginTime =System.currentTimeMillis();11 for (int i = 0; i < count; i++) {12 String s =String.valueOf(num);13 }14 endTime =System.currentTimeMillis();15 System.out.println("String.valueOf()的方式耗时: " + (endTime - beginTime) + "ms");16

17 beginTime =System.currentTimeMillis();18 for (int i = 0; i < count; i++) {19 String s =num.toString();20 }21 endTime =System.currentTimeMillis();22 System.out.println("toString()的方式耗时: " + (endTime - beginTime) + "ms");

结果:

+号拼接的方式耗时: 30ms

String.valueOf()的方式耗时: 6ms

toString()的方式耗时: 5ms

以上示例中

String.valueOf()直接调用了底层的Integer.toString()方法,会先判空;

+号拼接由StringBuilder实现,先调用了append()方法,然后调用了toString()方法获取字符串;

num.toString()直接调用了Integer.toString()方法,

所以效率是:

num.toString()方法最快,

其次是String.valueOf(num),最后是加号拼接的方式。

避免使用加号拼接的方式转换,最好是使用基本数据类型自带的toString()方法转换。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值