一、Java String 类——String字符串常量
简介
- String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,这样不仅效率低下,而且大量浪费有限的内存空间,所以经常改变内容的字符串最好不要用 String 。
- 因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。
- 与包装类类似,String类也是不可变类,即对象一旦创建,就没有办法修改了。String类也声明为了final,不能被继承,内部char数组value也是final的,初始化后就不能再变了。
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
/**
*The value is used for character storage.
*/
private final char value[];
- String 是 final 类,不能被继承。对于已经存在的 Stirng 对象,修改它的值,就是重新创建一个对象
- String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量优先的内存空间
String 对象的两种创建方式。
String str1="abcd";
String str2=new String("abcd");
System.out.println(str1==str2);// false
- 这两种不同的创建方法是有差别的,第一种方式是在常量池中那对象。
-
第二种方式是直接在对内存空间创建一个新的对象。
String pool ,String 类型的常量池比较特殊。
- 检查字符串池里面有没有“XXX”的内容,如果有,则不会从创建新的字符串对象。将已有对象的地址返回给那个引用。
- 直接使用双引号声明出来的String对象会直接存储在常量池中。
- 如果不是用双引号声明的String对象,可以使用String提供的intern方法。String.intern()是一个Native方法,它的作用是:
如果运行时常量池中已经包含一个等于词String对象内容的字符串,则返回常量池中该字符串的引用;
如果没有,则在常量池中创建与此String内容相同的字符串,并返回常量池中创建的字符串的引用。
String s1 = new String("计算机");
String s2 = s1.intern();
String s3 = "计算机";
System.out.println(s2); // 计算机
System.out.println(s1==s2); // false 因为一个是堆内存中的String对象,一个是常量池中的String对象。
System.out.println(s2==s3);// true 应为两个都是常量池中的对象。
String 字符串拼接
String str1 = "str";
String str2 = "ing";
String str3 = "str"+"ing"; // 常量池中的对象
String str4 = str1+str2; // 在堆上创建的新的对象
String str5 = "string"; // 在常量池中的对象
System.out.println(str3==str4); // false
System.out.println(str3==str5); // true
System.out.println(str4==str5); // false
String s1 = new String("abc"); // 这句话创建了几个对象 ?
- 创建了两个对象。
- “abc”这个是常量池对象
- 只要使用 new 便是创建新的对象
String.format()占位符替换
String常用函数
//判断字符串是否为空
public boolean isEmpty()
//获取字符串长度
public int length()
//取子字符串 截取
public String substring(int beginIndex)
public String substring(int beginIndex, int endIndex)
//在字符串中查找字符或子字符串,返回第一个找到的索引位置,没找到返回-1
public int indexOf(int ch)
public int indexOf(String str)
//从后面查找字符或子字符串,返回从后面数的第一个索引位置,没找到返回-1
public int lastIndexOf(int ch)
public int lastIndexOf(String str)
//判断字符串中是否包含指定的字符序列。回顾一下,CharSequence是一个接口,String也实现了CharSequence
public boolean contains(CharSequence s)
//判断字符串是否以给定子字符串开头
public boolean startsWith(String prefix)
//判断字符串是否以给定子字符串结尾
public boolean endsWith(String suffix)
//与其他字符串比较,看内容是否相同
public boolean equals(Object anObject)
//忽略大小写,与其他字符串进行比较,看内容是否相同
public boolean equalsIgnoreCase(String anotherString)
//String也实现了Comparable接口,可以比较字符串大小
public int compareTo(String anotherString)
//还可以忽略大小写,进行大小比较
public int compareToIgnoreCase(String str)
//所有字符转换为大写字符,返回新字符串,原字符串不变
public String toUpperCase()
//所有字符转换为小写字符,返回新字符串,原字符串不变
public String toLowerCase()
//字符串连接,返回当前字符串和参数字符串合并后的字符串,原字符串不变
public String concat(String str)
//字符串替换,替换单个字符,返回新字符串,原字符串不变
public String replace(char oldChar, char newChar)
//字符串替换,替换字符序列,返回新字符串,原字符串不变
public String replace(CharSequence target, CharSequence replacement)
//删掉开头和结尾的空格,返回新字符串,原字符串不变
public String trim()
//分隔字符串,返回分隔后的子字符串数组,原字符串不变
public String[] split(String regex)
//例如,按逗号分隔"hello,world":
String str = "hello,world";
String[] arr = str.split(","); //arr[0]为"hello", arr[1]为"world"。
二、StringBuffer
- Java.lang.StringBuffer线程安全的可变字符序列。
- 一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
- 可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。
- StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。
三、StringBuilder
- java.lang.StringBuilder一个可变的字符序列是5.0新增的。
- 此类提供一个与 StringBuffer 兼容的 API,但不保证同步。
- 该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。
四、StringBuffer与StringBuilder的线程安全性问题
- StringBuffer和StringBuilder可以算是双胞胎了,这两者的方法没有很大区别。但在线程安全性方面,StringBuffer允许多线程进行字符操作。这是因为在源代码中StringBuffer的很多方法都被关键字synchronized 修饰了,而StringBuilder没有。
- 注意:是不是String也不安全呢?事实上不存在这个问题,String是不可变的。线程对于堆中指定的一个String对象只能读取,无法修改。试问:还有什么不安全的呢?
网友评论