类:String、StringBuffer、StringBuilder
1.区分String、StringBuffer、StringBuilder
String:字符串常量
StringBuffer:字符串变量(线程安全)
StringBuilder:字符串变量(非线程安全,速度快)
简要的说, String 类型和StringBuffer 类型的主要性能区别其实在于String 是不可变的对象,因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的String 对象,然后将指针指向新的String 对象,所以经常改变内容的字符串最好不要用String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后,JVM 的 GC 就会开始工作,那速度是一定会相当慢的。而如果是使用StringBuffer 类则结果就不一样了,每次结果都会对StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用StringBuffer ,特别是字符串对象经常改变的情况下。在对象不需要同步机制支持的情况下,StringBuilder是StringBuffer的良好替代。
在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了StringBuffer 对象的拼接,所以这些时候String 对象的速度并不会比StringBuffer 对象慢,而特别是以下的字符串对象生成中,String效率是远要比StringBuffer 快的。
String S1= “This is only a” + “ simple” + “ test”;
StringBufferSb = new StringBuilder(“This is only a”).append(“simple”).append(“ test”);
你会很惊讶的发现,生成String S1 对象的速度简直太快了,而这个时候StringBuffer 居然速度上根本一点都不占优势。其实这是JVM 的一个把戏,在 JVM 眼里,这个
String S1= “This is only a” + “ simple” + “test”;
其实就是:
String S1= “This is only a simple test”;
所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的String 对象的话,速度就没那么快了,譬如:
String S2= “This is only a”;
String S3= “ simple”;
String S4= “ test”;
String S1= S2 +S3 + S4;
这时候 JVM 会规规矩矩的按照原来的方式去做。
Java.lang.StringBuffer线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
这三个类都是 final类型,不能被继承。
StringBuilder和StringBuffer常用方法:capacity() length() append(XX xx) insert(int offset, XXxx) delete(int start, int end) deleteCharAt(int index) charAt(int index) indexOf(String str)indexOf(String str, int fromIndex)lastIndexOf replace(int start, int end, Stringstr) reverse()。
2.String常用方法:
trim() 去掉前导和尾部空白
replacerelaceAllreplaceFirst str.replaceAll("a","b");不会改变str的值,replaceAll返回的是String类型,要改变str值,要写成str=str.replaceAll("a","b");
3.字符串判等之“==”与“equals”
①首先String不属于8种基本数据类型,String是一个对象。因为对象的默认值是null,所以String的默认值也是null;但它又是一种特殊的对象,有其它对象没有的一些特性。
② newString()和newString(“”)都是申明一个新的空字符串,是空串不是null;
③ Stringstr=”kvill”与Stringstr=new String (“kvill”)的区别:
在这里,我们不谈堆,也不谈栈,只先简单引入常量池这个简单的概念。常量池(constantpool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。常量池实际上是堆中一小块空间,对基本数据类型和String等在编译期间就能确定值的变量进行存储,具体参考:百度百科常量池http://baike.baidu.com/view/8680346.htm。
。
看例1:
Strings0=”kvill”;
Strings1=”kvill”;
Strings2=”kv” + “ill”;
System.out.println(s0==s1 );
System.out.println(s0==s2 );
结果为:
true
true
首先,我们要知道Java会确保一个字符串常量只有一个拷贝。因为例子中的s0和s1中的”kvill”都是字符串常量,它们在编译期就被确定了,所以s0==s1为true;而”kv”和”ill”也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以s2也同样在编译期就被解析为一个字符串常量,所以s2也是常量池中”kvill”的一个引用。所以我们得出s0==s1==s2;用newString() 创建的字符串不是常量,不能在编译期就确定,所以newString()创建的字符串不放入常量池中,它们有自己的地址空间。
看例2:
Strings0=”kvill”;
Strings1=new String(”kvill”);
Strings2=”kv” + new String(“ill”);
System.out.println(s0==s1 );
System.out.println(s0==s2 );
System.out.println(s1==s2 );
结果为:
false
false
false
例2中s0还是常量池中”kvill”的应用,s1因为无法在编译期确定,所以是运行时创建的新对象”kvill”的引用,s2因为有后半部分newString(“ill”)所以也无法在编译期确定,所以也是一个新创建对象”kvill”的应用;明白了这些也就知道为何得出此结果了。
4. String.intern()
再补充介绍一点:存在于.class文件中的常量池,在运行期被JVM装载,并且可以扩充。String的intern()方法就是扩充常量池的一个方法;当一个String实例str调用intern()方法时,Java查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用,如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用;看例3就清楚了。
例3:
Strings0= “kvill”;
Strings1=new String(”kvill”);
Strings2=new String(“kvill”);
System.out.println(s0==s1 );
s1.intern();
s2=s2.intern();//把常量池中“kvill”的引用赋给s2
System.out.println(s0==s1);
System.out.println(s0==s1.intern() );
System.out.println(s0==s2 );
结果为:
false
false //虽然执行了s1.intern(),但它的返回值没有赋给s1
true //说明s1.intern()返回的是常量池中”kvill”的引用
true
最后我再破除一个错误的理解:有人说,“使用String.intern()方法则可以将一个String类的保存到一个全局String表中,如果具有相同值的Unicode字符串已经在这个表中,那么该方法返回表中已有字符串的地址,如果在表中没有相同值的字符串,则将自己的地址注册到表中“如果我把他说的这个全局的String表理解为常量池的话,他的最后一句话,“如果在表中没有相同值的字符串,则将自己的地址注册到表中”是错的。
看例4:
Strings1=new String("kvill");
Strings2=s1.intern();
System.out.println(s1==s1.intern() );
System.out.println(s1+" "+s2 );
System.out.println(s2==s1.intern() );
结果:
false
kvillkvill
true
在这个类中我们没有声名一个”kvill”常量,当我们调用s1.intern()后就在常量池中新添加了一个”kvill”常量,原来的不在常量池中的”kvill”仍然存在,也就不是“将自己的地址注册到常量池中”了。s1==s1.intern()为false说明原来的“kvill”仍然存在;s2现在为常量池中“kvill”的地址,所以有s2==s1.intern()为true。
5. 关于equals()和==
这个对于String简单来说就是比较两字符串的Unicode序列是否相当,如果相等返回true;而==是比较两字符串的地址是否相同,也就是是否是同一个字符串的引用。
6. 关于String是不可变的
这一说又要说很多,大家只要知道String的实例一旦生成就不会再改变了,比如说:Stringstr=”kv”+”ill”+” “+”ans”; 就是有4个字符串常量,首先”kv”和”ill”生成了”kvill”存在内存中,然后”kvill”又和” “生成 ”kvill “存在内存中,最后又和生成了”kvillans”;并把这个字符串的地址赋给了str,就是因为String的“不可变”产生了很多临时变量,这也就是为什么建议用StringBuffer的原因了,因为StringBuffer是可改变的。
7. 不同操作系统下的换行符
java中写入文件时换行符是用"\r\n"还是"\n"?
\r 叫回车Carriage Return ;
\n 叫新行New Line 。
但是都会造成换行,使用System.getProperty("line.separator")来获取当前OS的换行符,可以在调试的情况下看到!
各系统换行符应当是:
\r Mac
\nUnix/Linux
\r\nWindows
可以用replaceAll方法转换:str =str.replaceAll("\n", "\r\n");
参考:http://www.cnblogs.com/tjuximo/archive/2011/03/25/1995458.html