String

String s1 = new String("abc");
String s2 = "abc";

第一,在堆中创建一个String对象,他的value为abc,检查到常量池没有abc这个字符串,于是在字符串常量池中创建并将其关联到String对象上。将这个String对象的内存地址值,赋值给栈中S1变量。

第二行中,检查到常量池中已经存在abc这个字符串,所以直接将地址赋给了变量s2.

至于底层如何关联,可以理解为String中有个value属性,可以通过它进行关联。至于详细讲述,感兴趣的话可以自行查阅《Java编程思想》之类的书籍。

建议先建立知识体系为主,旁枝末节容后再议

  • 字符串对象一旦被初始化就不会被改变
  • 字符串存在字符串常量池中,池中没有就建立,有就直接使用
String s1 = "abc"; //s1在栈中
String s2 = "abc";
String s3 = new String("abc"); //s3在堆中
s1==s2  //true
s1==s3 //false
s1.equals(s3) //true  //String重写了equals,比较内容

String string = new String();
String string2 = "";
System.out.println(string==string2); //false

常用方法

public class TestString {
	public static void main(String[] args) {
		String string="abc";
		System.out.println(string);
		//charAt
		System.out.println(string.charAt(1));
		//indexOf
		System.out.println(string.indexOf('b')); //char自动转换为int
		System.out.println(string.indexOf("bc")); //字符串
		System.out.println(string.indexOf(98)); //int
		System.out.println(string.indexOf('l')); //-1
		//lastIndexOf
		String string2 = "helloworld";
		System.out.println(string2.indexOf('o',5)); //6
		System.out.println(string2.lastIndexOf('o',3)); //-1 //反向搜索
		//replace 不改变原字符串 只操作了方法区的常量池
		System.out.println(string2.replace('o', 'p')); //hellpwprld
		System.out.println(string2); //helloworld
		//substring 不改变原字符串 只操作了方法区的常量池
		System.out.println(string2.substring(3)); //loworld  一直到结尾
		System.out.println(string2.substring(3,7)); //lowo 含头不含尾
		System.out.println(string2); //helloworld
		//toUpperCase toLowerCase 不改变原字符串 只操作了方法区的常量池
		System.out.println(string2.toUpperCase()); //HELLOWORLD
		System.out.println(string2); //helloworld
		System.out.println("JAVA".toLowerCase()); //java
		//trim 去掉前后空格 不改变原字符串 只操作了方法区的常量池
		String string3 = "     hello   world";
		System.out.println(string3.trim()); //hello   world
		System.out.println(string3); //     hello   world
		//split
		String string3 = "1,2,3,4,5";
		String[] arr = string3.split(",");
		System.out.println(Arrays.toString(arr)); //[1, 2, 3, 4, 5]
		//toCharArray
		String string4 = "abbccdde";
		System.out.println(Arrays.toString(string4.toCharArray())); //[a, b, b, c, c, d, d, e].
		//getBytes
		String string5 = "abbccdde";
		byte[] b = string5.getBytes();
		System.out.println(Arrays.toString(b)); //[97, 98, 98, 99, 99, 100, 100, 101]
	}
}

构造器

/*String的构造方法*/
String s1 = new String(); //创建了长度为0的字符串
String s2=null;//没有对象,只声明了栈变量
String s3 = new String("hello");
char[] c= {'a','b','c'};
String s4 = new String (c);
byte[] b= {97,98,99};
String s5=new String(b);
String s6 = new String(c,0,2); //开始位置,个数
String s7 = new String(b,0,2);
System.out.printf("s1=%s,s2=%s,s3=%s,s4=%s,s5=%s,s6=%s,s7=%s", s1,s2,s3,s4,s5,s6,s7);
//s1=,s2=null,s3=hello,s4=abc,s5=abc,s6=ab,s7=ab

String 内存 常量池

String str1 = "abc";
String str2 = "a"+"b"+"c";
String str3 = new String("abc");
String str4 = str3+"";
String str5 = new String("abc");
System.out.println();
System.out.println("str1==str2:"+(str1==str2)); //str1==str2:true
System.out.println("str1==str3:"+(str1==str3)); //str1==str3:false
System.out.println("str1==str4:"+(str1==str4)); //str1==str3:false
System.out.println("str1==str5:"+(str1==str5)); //str1==str3:false

Java中的String为什么是不可变的? -- String源码分析 String:字符串常量池 java字符串常量值 String对象在Java的堆和常量池中的情况 JDK1.8版本java字符串常量池里存的是String对象还是引用? java内存分配和String类型的深度解析

字符串比较

boolean equals(Object obj) //比较内容 boolean equalsIgnoreCase(Object obj) boolean contains(String str) //内部实现 indexof startsWith endsWith

//equalsIgnoreCase
System.out.println(string.equalsIgnoreCase("ABC"));
//startsWith endsWith
System.out.println(string2.startsWith("h")); //true
System.out.println(string2.endsWith("d")); //true

equals

compareto 构造方法

/*compareTo*/
String aString = "apple";
String bString = "banana";
String catString = "cat";
String aString2 = "app";
//求两个字符串长度的最小值,循环,比较对应位置上的字母,如果不相同,则返回对应位置字母ASCII的差,如果在最小长度内都相同,则返回两个字符串的长度差
System.out.println(aString.compareTo(bString)); //-1
System.out.println(aString.compareTo(catString)); //-2
System.out.println(aString.compareTo(aString2)); //2

intern

获取常量池中字符串对象,没有则创建

String string = new String("abc");
String string2 = string.intern();  //string2="abc";
System.out.println(string2);
System.out.println(string==string2); //false

练习

//排序
String[] string = {"ab","bc","ce","cd"};
Arrays.sort(string);
System.out.println(Arrays.toString(string));

//查找子串的次数
String str = "nbasfafsdanbasdfaasnbafafasnbaafd";
String key = "nba";
int index = 0;
int count = 0;
while((index = str.indexOf(key, index))!=-1) {
	index = index + key.length();
	count++;
}
System.out.println(count);

//获取最大子串
String s1 = "qwerabcdtyuiop";
String s2 = "xcabcdvbn";
outer:
for(int i=0;i<s2.length();i++) {
	for(int a=0,b=s2.length()-i;b!=s2.length()+1;a++,b++) {
		String subString = s2.substring(a,b);
		if(s1.contains(subString)) {
			System.out.println(subString);
			break outer;
		}
	}
}
//去掉两头空格
String string2 = "    abc    ";
int start = 0;
int end = string2.length()-1;

while(start<=end && string2.charAt(start)==' ') {
	start++;
}
while(start<=end && string2.charAt(end)==' ') {
	end--;
}

System.out.println(string2.substring(start,end+1));

StringBuffer

字符串缓冲区,用于存储数据的容器

  • 长度可变
  • 可以存储不同类型的数据
  • 初始容量为16,超过16会复制长度乘以2
  • 可以修改
  • 线程同步
StringBuffer sBuffer = new StringBuffer();

//添加
StringBuffer sBuffer2 = sBuffer.append(1).append(true);
System.out.println(sBuffer); //1true
System.out.println(sBuffer==sBuffer2); //true

sBuffer.insert(1, "haha");
System.out.println(sBuffer); //1hahatrue

//删除
sBuffer.delete(1, 3);
System.out.println(sBuffer); //1hatrue

//查找 charAt indexOf lastIndexOf

//修改
sBuffer.replace(1, 3, "nba");
sBuffer.setCharAt(4, 'y');
System.out.println(sBuffer);

System.out.println(sBuffer.reverse());

sBuffer.setLength(0);
System.out.println(sBuffer.length());

StringBuilder

线程不同步,不安全 解决StringBuffer需要判断锁的效率问题,适用于单线程 自动扩容 默认char[]16长度,大于16则乘以2再加2,如果大于34,则继续

StringBuilder sBuilder = new StringBuilder();
sBuilder.append("helloworld");
sBuilder.append("world");
sBuilder.append("world");
sBuilder.append("world");
sBuilder.append("world");
sBuilder.append("world");
sBuilder.append("world");

System.out.println(sBuilder.length()); //40
System.out.println(sBuilder.capacity()); //70  (16*2+2)*2+2

StringBuilder比String连接效率高,因为连接其实也是用StringBuilder实现,还需要中间转换

public class Test {
	public static void main(String[] args) {
		
		String string = "";
		for(int i=0;i<10;i++) {
			string = string+i;
		}
		System.out.println(string);
		
		StringBuilder sBuilder = new StringBuilder();
		for(int i=0;i<10;i++) {
			sBuilder.append(i);
		}
		System.out.println(sBuilder);
	}
}


书籍推荐