相信String这个类是Java中使用得最频繁的类之一,今天就来和大家一起学习一下String、StringBuilder和StringBuffer。
一、从源码的角度初步了解String类
想要了解一个类,最好的办法就是看这个类的实现源代码,打开这个类的源码文件就会发现String类是被final修饰的:
进一步分析可以看出几点:
1)String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。在早期的JVM实现版本中,被final修饰的方法会被转为内嵌调用以提升执行效率。而从Java SE5/6开始,就渐渐摈弃这种方式了。因此在现在的Java SE版本中,不需要考虑用final去提升方法调用效率。只有在确定不想让该方法被覆盖时,才将方法设置为final。
2)源码中String类中的成员属性可以看出,String类其实是通过char数组来保存字符串的。
3)从上面的两个方法可以看出,无论是sub还是concat操作都不是在原有的字符串上进行的,而是重新生成了一个新的字符串对象。也就是说进行这些操作后,最原始的字符串并没有被改变。
在这里要永远记住一点:
“对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象”。
在了解了于String类基础的知识后,下面来看一些在平常使用中容易忽略和混淆的地方。
二.深入理解String、StringBuffer、StringBuilder
1.String str=”hello world”和String str=new String(“hello world”)的区别
import java.util.Objects; public class Demo { public static void main(String[] args) { String s1 = "hello"; String s2 = new String("hello"); String s3 = "hello"; String s4 = new String("hello"); System.out.println(s1 == s2);//false System.out.println(s1 == s3);//true System.out.println(s2 == s4);//false } }
2.String、StringBuffer以及StringBuilder的区别
StringBuffer以及StringBuilder的功能和String一样都是可以进行字符串的操作。
既然在Java中已经存在了String类,那为什么还需要StringBuilder和StringBuffer类呢?
那么看下面这段代码:
import java.util.Objects; public class Demo { public static void main(String[] args) { String string = ""; for (int i = 0; i < 100; i++) { string += "hello";// string = string + hello //传统的String做字符串拼接,循环100次,new100字符串对象 } System.out.println(string); } }
从上面String的源码中我们可以分析出:这句 string += “hello”;的过程相当于将原有的string变量指向的对象内容取出与“hello”作字符串相加操作再存进另一个新的String对象当中,再让string变量指向新生成的对象。也就是说这个循环执行完毕new出了10000个对象,试想一下,如果这些对象没有被回收,会造成多大的内存资源浪费。
再看下面这段代码:
import java.util.Objects; public class Demo { public static void main(String[] args) { StringBuilder sbBuilder = new StringBuilder(); for (int i = 0; i < 100; i++) { sbBuilder.append("hello"); } System.out.println(sbBuilder.toString()); } }
这断代码和前面的功能一样,但是这里的10000次循环new操作只进行了一次,也就是说只生成了一个对象,append操作是在原有对象的基础上进行的。因此在循环了10000次之后,这段代码所占的资源要比上面小得多。这就是String和stringBuilder的最最主要的区别。
其实:字符串拼接从jdk5开始编译器就已经完成了自动优化,当String+常量的代码在编译的时候就会自动被优化为new一个StringBuilder,再调用append方法。
那么有人会问既然有了StringBuilder类,为什么还需要StringBuffer类?查看源代码便一目了然,事实上,StringBuilder和StringBuffer类拥有的成员属性以及成员方法基本相同,区别是StringBuffer类的成员方法前面多了一个关键字:synchronized,不用多说,这个关键字是在多线程访问时起到安全保护作用的,也就是说StringBuffer是线程安全的。有关线程的问题,我们讲多线程的时候在详细讲解!
总结:这三个类是各有利弊,应当根据不同的情况来进行选择使用
1、循环外字符串拼接可以直接使用String的+操作,没有必要通过StringBuilder进行append.
2、有循环体的话,好的做法是在循环外声明StringBuilder对象,在循环内进行手动append。
不论循环多少层都只有一个StringBuilder对象。
3、当字符串相加操作较多的情况下,建议使用StringBuilder,如果采用了多线程,则使用StringBuffer。
相信String这个类是Java中使用得最频繁的类之一,今天就来和大家一起学习一下String、StringBuilder和StringBuffer。
一、从源码的角度初步了解String类
想要了解一个类,最好的办法就是看这个类的实现源代码,打开这个类的源码文件就会发现String类是被final修饰的:
进一步分析可以看出几点:
1)String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。在早期的JVM实现版本中,被final修饰的方法会被转为内嵌调用以提升执行效率。而从Java SE5/6开始,就渐渐摈弃这种方式了。因此在现在的Java SE版本中,不需要考虑用final去提升方法调用效率。只有在确定不想让该方法被覆盖时,才将方法设置为final。
2)源码中String类中的成员属性可以看出,String类其实是通过char数组来保存字符串的。
3)从上面的两个方法可以看出,无论是sub还是concat操作都不是在原有的字符串上进行的,而是重新生成了一个新的字符串对象。也就是说进行这些操作后,最原始的字符串并没有被改变。
在这里要永远记住一点:
“对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象”。
在了解了于String类基础的知识后,下面来看一些在平常使用中容易忽略和混淆的地方。
二.深入理解String、StringBuffer、StringBuilder
1.String str=”hello world”和String str=new String(“hello world”)的区别
public class Main {
public static void main(String[] args) {
String str1 = “hello world”;
String str2 = new String(“hello world”);
String str3 = “hello world”;
String str4 = new String(“hello world”);
System.out.println(str1==str2);
System.out.println(str1==str3);
System.out.println(str2==str4);
}
}
这段代码的输出结果为
2.String、StringBuffer以及StringBuilder的区别
StringBuffer以及StringBuilder的功能和String一样都是可以进行字符串的操作。
既然在Java中已经存在了String类,那为什么还需要StringBuilder和StringBuffer类呢?
那么看下面这段代码:
public class Main {
public static void main(String[] args) {
String string = “”;
for(int i=0;i<10000;i++){
string += “hello”;
}
}
}
从上面String的源码中我们可以分析出:这句 string += “hello”;的过程相当于将原有的string变量指向的对象内容取出与“hello”作字符串相加操作再存进另一个新的String对象当中,再让string变量指向新生成的对象。也就是说这个循环执行完毕new出了10000个对象,试想一下,如果这些对象没有被回收,会造成多大的内存资源浪费。
再看下面这段代码:
public class Main {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder();
for(int i=0;i<10000;i++){
stringBuilder.append(“hello”);
}
}
}
这断代码和前面的功能一样,但是这里的10000次循环new操作只进行了一次,也就是说只生成了一个对象,append操作是在原有对象的基础上进行的。因此在循环了10000次之后,这段代码所占的资源要比上面小得多。这就是String和stringBuilder的最最主要的区别。
其实:字符串拼接从jdk5开始编译器就已经完成了自动优化,当String+常量的代码在编译的时候就会自动被优化为new一个StringBuilder,再调用append方法。
那么有人会问既然有了StringBuilder类,为什么还需要StringBuffer类?查看源代码便一目了然,事实上,StringBuilder和StringBuffer类拥有的成员属性以及成员方法基本相同,区别是StringBuffer类的成员方法前面多了一个关键字:synchronized,不用多说,这个关键字是在多线程访问时起到安全保护作用的,也就是说StringBuffer是线程安全的。有关线程的问题,我们讲多线程的时候在详细讲解!
总结:这三个类是各有利弊,应当根据不同的情况来进行选择使用
1、循环外字符串拼接可以直接使用String的+操作,没有必要通过StringBuilder进行append.
2、有循环体的话,好的做法是在循环外声明StringBuilder对象,在循环内进行手动append。
不论循环多少层都只有一个StringBuilder对象。
3、当字符串相加操作较多的情况下,建议使用StringBuilder,如果采用了多线程,则使用StringBuffer。
最新评论