什么是字符串?如果直接按照字面意思来理解就是多个字符连接起来组合成的字符序列。为了更好的理解以上的理论,我们先来解释下字符序列,字符序列:把多个字符按照一定的顺序排列起来;而字符序列就是作为字符串的内容而存在的。所以可以把字符串理解为:把多个字符按照一定的顺序排列起来而构成的排列组合。
如果还是不好理解,没有关系,我还有法宝。我们可以用烤串来比喻说明,可以把字符串看作是烤串,烤串上的每一块肉都相当于是一个字符。把一块块肉按照肥瘦相间的顺序排列并串起来便成了我们吃的烤串,同理,把多个字符按照一定的顺序“串”起来就构成了字符串。
字符串的分类,字符串分为可变的字符串和不可变的字符串两种;这里的不可变与可变指的是字符串的对象还是不是同一个,会不会因为字符串对象内容的改变而创建新的对象。
String类表示不可变的字符串,当前String类对象创建完毕之后,该对象的内容(字符序列)是不变的,因为内容一旦改变就会创建一个一个新的对象。
以上两种创建方式的对象在JVM中又是如何分布的呢? 分别有什么区别呢?
方式一和方式二在JVM中又是如何分布?
上图中的常量池:用于存储常量的地方内存区域,位于方法区中。常量池又分为编译常量池和运行常量池两种:
字符串的本质,字符串在底层其实就是char[],char表示一个字符,比如:
String str ="laofu";
// 等价于
char[] cs =newchar[]{'l','a','o','f','u'};
字符串的比较,使用"=="和"equals"会有不同效果:
所以可以这样来判断字符串非空:
如果上述两个条件都满足,说明字符串确实为空!
字符串拼接:Java中的字符串可以通过+实现拼接,那么代码中字符串拼接在JVM中又是如何处理的呢?我们通过一个例子说明:通过比较拼接字符串代码编译前后的代码来查看JVM对字符串拼接的处理。
通过上述例子不难发现,JVM会对字符串拼接做一些优化操作,如果字符串字面量之间的拼接,无论有多少个字符串,JVM都会一样的处理;如果是对象之间拼接,或者是对象和字面量之间的拼接,亦或是方法执行结果参与拼接,String内部会使用StringBuilder先来获取对象的值,然后使用append方法来执行拼接。由此可以总结得出:
这里列举了一些常用String API,更多的可以查阅jdk使用手册,做Java一定得学会查阅jdk手册。
String 的创建和转换:
// 把字符串转换为byte数组。
byte[] getBytes();
// 把字符串转换为char数组。
char[] toCharArray();
// 把byte数组转换为字符串。
String(byte[] bytes);
// 把char数组转换为字符串。
String(char[] value);
获取字符串信息:
// 返回此字符串的长度。
int length();
// 返回指定索引处的 char 值。
char charAt(int index);
// 返回指定字符串在此字符串中首次(从最左边算起)出现处的索引。
int indexOf(String str);
// 返回指定字符串在此字符串中最后(最右边算起)出现处的索引。
int lastIndexOf(String str);
字符串比较判断:
// 将此字符串与指定的对象比较。
boolean equals(Object anObject);
// 将此 String 与另一个 String 做忽略大小写的比较。
boolean equalsIgnoreCase(String anotherString);
// 将此字符串与指定的 CharSequence 比较,比较的是内容;
// ps:String类是现实了CharSequence(字符序列)接口的。
boolean contentEquals(CharSequence cs);
字符串大小写转换:调用方法的字符串就是当前字符串
// 把当前字符串转换为大写
String toUpperCase();
// 把当前字符串转换为小写
String toLowerCase();
先来分别使用String/StringBuilder/StringBuffer来拼接30000次字符串,对比各自损耗的时间,经过测试发现:
所以在开发中拼接字符串时,优先考虑StringBuffer/StringBuilder,不要轻易使用String。
StringBuffer和StringBuilder都表示可变的字符串,他俩的功能方法都是相同的。但唯一的区别:
对并发安全没有很高要求的情况下,建议使用StringBuilder,因为其性能很高。像这样的情况会较多些。使用StringBuilder无参数的构造器,在底层创建了一个长度为16的char数组:
此时该数组只能存储16个字符,如果超过了16个字符,会自动扩容(创建长度更大的数组,再把之前的数组拷贝到新数组),此时性能极低;如果事先知道大概需要存储多少字符,可以通过构造器来设置字符的初始值:
// 创建一个长度为80的char数组.
new StringBuilder(80);
StringBuilder的常用方法:
// 追加任意类型数据到当前StringBuilder对象中。
append(Object val);
// 删除字符串中指定位置的字符。
StringBuilder deleteCharAt(int index);
完结,老夫虽不正经,但老夫一身的才华。