目录
String类的创建:
字符串就是用双引号引起来的一串字符。创建方式主要有三种:
String str = "abcdef"; //1、直接赋值
String str2 = new String("abcdef"); //2、new一个String对象
char[] array = {'a', 'b', 'c', 'd', 'e', 'f'}; //3、通过字符数组
String str3 = new String(array);
内存中的分布:
首先直接赋值的方式:字符常量都存放在常量池中,且仅此一份。
第二种方法:String底层实现有一个value[]数组,
拿到常量池中已经存在的的abcdef构造了String对象,String对象中有一个value[]数组,来保存abcdef的地址。产生了两个对象。
第三种方法:
String底层的构造方法如下图:
关于String类的典型内存分布
ps:==相对于基本类型比较值是否相等,相对于引用类型是比较地址是否相等。
String str1 = "abcdef";
String str2 = new String("abcdef");
System.out.println(str1 == str2); //1、false 上图可表明
String str3 = "abc" + "def";
System.out.println(str1 == str3); //2、true "abc" 和 "def"
都是字符常量,在编译时已经合并为abcdef,常量池中相同的字符串只能存在一份,因此str1和str3指
向同一块空间
String str4 = "abc" + new String("def");
System.out.println(str1 == str4); //3、false
String str5 = "abc";
String str6 = "def";
String str7 = str5+str6;
System.out.println(str1 == str7); //false 和第三个思想类似
String str8 = str5 + new String("def");
System.out.println(str1 == str8); //false 和第三个思想类似
第三个比较令人疑惑,其实它在内存中如下分布:
.intern()的使用
String str1 = "abcdef";
String str2 = new String("abcdef").intern();
System.out.println(str1 == str2);
天呐,上面代码运行出来竟然是true。。intern();方法还是非常强大的。作用为手动入池。
1、intern() 方法是一个native方法,底层是由C/C++实现的。
2、如果常量池当中存在将要入池的字符串,直接将常量池当中的字符串常量的地址返回
如果常量池不存在,那么在常量池当中将该字符串入池。
字符串的不可变性
一段代码:
String str = "hello";
str = str + "world";
str += "!!";
System.out.println(str);
这个代码打印出来肯定是 helloworld!! ,但是并不是修改了原来的str中的值,而是创建了新的对象,体现了字符串的不可变性。而且每次拼接都会产生新的对象。
那么为什么String要不可变:
1. 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑何时深拷贝字符串的问题了
2. 不可变对象是线程安全的
3. 不可变对象更方便缓存hash code,作为key可以更高效的保存在Hash Map中
如何有一个字符串"Hello",一定要把它改为"hello",那么就要用到反射了,反射需要先得到Class对象,存放在方法去,存放的是类的信息。具体方法如下:
public static void main(String[] args) throws NoSuchFieldException ,
IllegalAccessException{
String str = "Hello"; //new String()
Class cls = String.class; //获取class对象
Field field = cls.getDeclaredField("value"); //把str中的value获取到
field.setAccessible(true);
char[] value = (char[])field.get(str);
value[0] = 'h';
System.out.println(str);
}
字符、字节和字符串的转换
字符串和字符之间的转化:
1.字符转化为字符串
char[] array = {'a', 'b', 'c', 'd', 'e', 'f'};
String str3 = new String(array);
2.字符串转化为字符
String str = "abcdef";
char[] array = str.toCharArray();
字符串和字节的转化:
1.字节转化为字符串
byte[] bytes = {97, 98, 99, 100};
String str = new String(bytes);
System.out.println(str); //abcd
2.字符串转化为字节
String str1 = "白";
byte[] bytes1 = str1.getBytes("Unicode");
System.out.println(Arrays.toString(bytes1)); //获取字符串的编码方式
byte[] and char[] 的适用范围:
byte[] 是把 String 按照一个字节一个字节的方式处理, 这种适合在网络传输, 数据存储这样的场景下使用. 更适合 针对二进制数据来操作
char[] 是吧 String 按照一个字符一个字符的方式处理, 更适合针对文本数据来操作, 尤其是包含中文的时候
字符串的常用操作
1、字符串比较:
String str = "Hello";
String str1 = "hello";
System.out.println(str.equals(str1)); //false
System.out.println(str.equalsIgnoreCase(str1)); //true
System.out.println(str.compareTo(str1)); //-32
字符串比较有三种方法,equals是比较字符串的值是否相等区分大小写,.equalsIgnoreCase不区分大小写。而compareTo()返回一个整型。
2、字符串查找
String str = "abcdefg";
//是否包含 底层调用indexOf()函数
System.out.println(str.contains("def")); //true
//查找子串-》返回下标
System.out.println(str.indexOf("bcd")); //1
//从后往前查找子串-》返回下标
System.out.println(str.lastIndexOf("cd")); //2
//判断是否以指定字符串开头
System.out.println(str.startsWith("ab")); //true
//判断是否以指定字符串结束
System.out.println(str.endsWith("ef")); //false
3、 字符串替换
String str = "abcabcba";
System.out.println(str.replace('a','A')); //AbcAbcbA
System.out.println(str.replace("ab","##")); //##c##cba
System.out.println(str.replaceAll("ab","##")); //##c##cba
System.out.println(str.replaceFirst("abc","**")); //**abcba
4、字符串拆分
String str = "a,bc ab,c b,a";
//[a,bc, ab,c, b,a]
String[] string = str.split(" "); //以空格为间隔符进行拆分
for (int i = 0; i < string.length; i++) {
String[] string2 = string[i].split(",");
// [a, bc]
//[ab, c]
//[b, a]
System.out.println(Arrays.toString(string2));
}
String str = "a,bc ab,c b,a";
//[a,bc, ab,c,b,a]
String[] string = str.split(" ",2); //所要分得的组数最大是2
注意有些特殊字符作为分隔符可能无法正确拆分,需要加上转义。
String str = "193.168.1.1";
String[] strings = str.split("\\.");
for (int i = 0; i < strings.length; i++) {
System.out.println(strings[i]);
}
注意:第一个\表示把 "\\" -> "\",第二个"\"是正则表达式"\." -> "."
字符"|","*","+"也是这样的规则,并且当一个字符串中有多个分隔符时,可以用"|"作为连字符。
5、字符串截取
String str = "abcdefg";
System.out.println(str.substring(2)); //cdefg
System.out.println(str.substring(2,5)); //左闭右开 cde
6、其他操作
1)去掉字符串左右的空格,保留中间空格
String str = " abc d e ";
System.out.println(str.trim()); //abc d e
2)大小写转换
String str = "abCDEFg";
System.out.println(str.toUpperCase()); //ABCDEFG
System.out.println(str.toLowerCase()); //abcdefg
3)字符串入池操作
char[] array = {'a', 'b', 'c'};
String str = new String(array);
str.intern();
4)字符串连接,等同于“+”,不入池
String str = "hello";
System.out.println(str.concat("Java")); //helloJava
5)判断字符串是否为空,取得字符串长度
String str = "";
System.out.println(str.isEmpty()); //true
System.out.println(str.length()); // 0 注意是方法
StringBuffer和StringBuilder
任何字符串常量就是String对象,而且String的常量一旦声明不可改变,如果改变对象内容,改变的只是引用的指向。由于字符串的不可变性,为了方便字符串的修改,提供StringBuffer和StringBuilder类,这两个大部分功能是相同的。
String的拼接底层会优化为StringBuilder
public static void main(String[] args) {
String str = "abc";
String str2 = str + "def";
System.out.println(str2);
}
StringBuilder的拼接并没有产生新的对象,是在原来对象进行修改。append();方法实现
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("abc");
System.out.println(sb); //abc
sb.append("java");
System.out.println(sb); // abcjava
}
ps:解释String、StringBuffer、StringBuilder的区别
1、String的内容不可修改,StringBuffer、StringBuilder的内容可以修改。
2、StringBuffer、StringBuilder使用方法是一样的,但是StringBuffer线程安全,String和StringBuilder线程不安全
3、String之间的拼接底层优化为了StringBuilder(append();方法)。StringBuffer、StringBuilder的append()不会产生新的对象(return this)
注意:String和StringBuffer不能直接转化,如果想要互相转化,可以:
String变为StringBuffer:利用StringBuffer的构造方法或append()方法
StringBuffer变为String:调用toString方法
字符串典型例题
1、输入两个字符串,需要无冗余拼接
public static String myAppend(String str) {
//分割
String[] strs = str.split(" ");
//String ret = "";
//for(String s : strs) {
// ret += s;
//}
//return ret;
StringBuilder sb = new StringBuilder();
for(String s : sb) {
sb.append(s);
}
return sb.toString();
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
System.out.println(myAppend(str));
}
2、将字符串进行逆置
//逆置字符串
public static String reverse(String string) {
char[] array = string.toCharArray();
int left = 0;
int right = array.length-1;
while (left < right) {
char tmp = array[left];
array[left] = array[right];
array[right] = tmp;
left++;
right--;
}
return String.copyValueOf(array);
}
public static void main(String[] args) {
String str = "abcdef";
String ret = reverse(str);
System.out.println(ret);
}
3、给定一个字符型的数组chas和一个整数size,请把大小为size的左半区整体右移到右半区,右半区整体移动到左边。
逆置前半部分-》逆置后半部分-》全部逆置
public static String reverse2(String str, int start, int end) {
char[] array = str.toCharArray();
while (start < end) {
char tmp = array[start];
array[start] = array[end];
array[end] = tmp;
start++;
end--;
}
return String.copyValueOf(array);
}
public static String fun(String str, int k) {
str = reverse2(str, 0, k-1);
str = reverse2(str, k,str.length()-1);
str = reverse2(str,0,str.length()-1);
return str;
}
public static void main(String[] args) {
String str = "abcdef";
System.out.println(fun(str,3)); //defabc
}
4、字符串的转化(压缩) aabbccda -》 2a2b2c1d1a
//字符串的转化(压缩) aabbccda -》 2a2b2c1d1a
public static String changeString(String str) {
char ch = str.charAt(0);
StringBuilder stringBuilder = new StringBuilder();
int count = 1;
for (int i = 1; i < str.length(); i++) {
if (ch == str.charAt(i)) {
count++;
} else {
stringBuilder.append(count).append(ch);
ch = str.charAt(i);
count = 1;
}
}
return stringBuilder.append(count).append(ch).toString(); //拷贝最后一组
}
public static void main17(String[] args) {
Scanner scanner = new Scanner(System.in);
String str = scanner.next();
System.out.println(changeString(str));
}
5、i am student -> stduent am i
//i am student -> stduent am i
//先整体逆置,再单词逆置
public static String reverseString(char[] array, int start, int end) {
while (start < end) {
char tmp = array[start];
array[start] = array[end];
array[end] = tmp;
start++;
end--;
}
return String.copyValueOf(array);
}
public static String fun(String str) {
char[] array = str.toCharArray();
//整体逆置
reverseString(array,0,str.length()-1);
//逆置单词
int i = 0;
int j = 0;
while (i < array.length) {
if (array[i] == ' ') {
i++;
j++;
} else if (j == array.length || array[j] == ' ') {
reverseString(array,i,j-1);
i = ++j;
} else {
j++;
}
}
return String.copyValueOf(array);
}
public static void main(String[] args) {
String str = "i am stdent";
System.out.println(fun(str));
}