Java之字符串

类: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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值