目录
1.String
String是不可变的对象
String常量池
String内存编码和长度
方法:indexof、substring、trim、chatAt、startswith和endswith
String是不可变对象
java.lang.String使用final修饰,不能被继承。
字符串底层封装字符数组及针对字符数组的操作算法。
字符串一旦创建,对象永远无法改变,但是字符串引用可以重新赋值。
java字符串在内存采用Unicode编码方式,任何一个字符对应两个字节的定长编码。
String常量池
字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程序的性能。
JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化。
- 为字符串开辟一个字符串常量池,类似于缓存区。
- 创建字符串常量时,首先坚持字符串常量池是否存在该字符串。
- 存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中。
实现的基础:
- 实现该优化的基础是因为字符串是不可变的,可以不用担心数据冲突进行共享。
- 运行时实例创建的全局字符串常量池中有一个表,总是为池中每个唯一的字符串对象维护一个引用,这就意味着它们一直引用着字符串常量池中的对象,所以,在常量池中的这些字符串不会被垃圾收集器回收java为了提高性能,静态字符串(字面量、常量、常量连接的结果)在常量池中创建,并尽量使用同一个对象,重用静态字符串。
**字符串常量池则存在于方法区。**静态区,跟堆一样,被所有的线程共享。方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。
字符串对象内部用字符数组进行存储的。
String m = "hello,world";
String n = "hello,world";
String u = new String(m);
String v = new String("hello,world");
操作过程:
会分配一个11长度的char数组,并在常量池分配一个由这个char数组组成的字符串,然后由m去引用这个字符串;用n去引用常量池里边的字符串,所以和n引用的是同一个对象;生成一个新的字符串,但内部的字符数组引用着m内部的字符数组;同样会生成一个新的字符串,但内部的字符数组引用常量池里边的字符串内部的字符数组,意思是和u是同样的字符数组。
结果:
m和n是同一个对象
m,u,v都是不同的对象
m,u,v,n但都使用了同样的字符数组,并且用equal判断的话也会返回true
内存编码及长度
String在内存中采用的是Unicode编码,每个字符占用两个字节;任何一个字符(无论中英文)都算1个字符长度,占用两个字节。
public void testlength(){
String s ="hello";
System.out.println(s.length());
}
indexOf
实现在字符串里检索另一个字符串
public void testindexOf(){
String s ="I can because I think I can ";
int i = s.indexOf("bec");
System.out.println(i);
int i2= s.indexOf("can");
System.out.println(i2);
}
substring获得子串
public void test1(){
String s ="I can because I think I can ";
String ss = str.substring(11,14);
System.out.println(ss);
}
trim
trim方法去掉字符串前后的空字符
public void test2(){
String s ="I can because I think I can ";
String ss = str.trim();
System.out.println(ss);
}
chatAt
chatAt方法用来返回字符串制定位置的字符,参数index用来制定位置。
public void test1(){
String s ="I can because I think I can ";
for(int i =0;i<s.length();i++){
char c = s.charAt(i);
System.out.println(c);
}
}
startsWith和endsWith
//检测一个字符串是不是以制定字符串为开头或结尾
public void test1(){
String s ="I can because I think I can ";
System.out.println(s.endsWith("cn"));
System.out.println(s.statsWith("I"));
}
StringBuilder
SBtringuilder封装可变得字符串,对象创建后可以通过调用改变其封装的字符序列。返回值都是StringBuilder类型(方法的返回语句都是return this)。
append和insert方法
//测试StringBuilder的append方法
public void test4(){
StringBuilder buf =new StringBulider("programming language");
buf.append("java").append("php").append("R")
System.out.println(buf.toString());
buf.insert(4,"python");
System.out.println(buf);
}
StringBuilder是可变字符串。在需要进行字符串的内容时候用StringBuilder进行实现会有更好的性能。
对比:
StringBuffer是线程安全的,同步处理的,性能稍慢;StringBuilder是非线程安全的,并发处理的,性能稍快。