1.构建字符串
String str1="abcdefg";//把字符串放到堆上面的字符串常量池里面了
String str2=new String("abcdefg");
char[] arr1={'a','b','c'};
String str3=new String(arr1);
字符串类型是 public final class String extends Object,他是不可变常量,是不可以被继承的
下面我们来看一下 String str=new String("hello")的内存布局;
2.字符串比较相同
1)我们在使用==比较字符串的时候并不是在进行比较字符串的内容,而是在比较两个引用是否指向了同一个对象
String str1="hello";
String str2="hello";
System.out.println(str1==str2);//str1与str2都会被放到字符串常量池里面,所以他们的引用是相同的
String str3=new String("hello");
String str4=new String("hello");
System.out.println(str3==str4);//字符串的内容虽然相同,但是new String("hello")都会在堆上面开辟内存
System.out.println(str1==str3);
2)所以我们在java中比较两个字符串是否相同,就要用到String类提供的equals方法
String str1=new String("hello");
String str2=new String("hello");
System.out.println(str1.equals(str2));//打印的结果是false
//下面是equals方法使用的一个注意事项
String str1=new String("hello");
System.out.println(str1.equals("hello"));
System.out.println("hello".equals(str1));
//我们此时更推荐的做法是方法二,一旦str是null,那么str1是null,那么代码1会抛出异常,但是代码2不会
String str1="hello";
String str2="hell"+"o";
String str3="he";
String str4=str3+"llo";
System.out.println(str1==str2);//true
System.out.println(str2==str4);//false
//在str2中,"he"与"llo"都是常量,编译的时候就会自动编译成”hello";
//但是在str4这个变量中str3是一个变量,编译器根本就不知道str3具体的值
3)手动入池
String str1=new String("hello").intern();
String str2="hello";
System.out.println(str1==str2);//打印结果是false
String str = "a"+"b"+"c"+"d";一共创建了几个对象?
该代码会被编译器编译时优化成"abcd",所以相当于String str = "abcd",所以只创建了一个对象
字符串常量池存于堆内存中(1.8之前是方法区)。
常见的常量池:
1)class文件常量池:
int a=10;这是磁盘上面的
2)运行时常量池:当程序把编译好的字节码文件,加载到JVM之后,会生成一个运行时常量池,他在方法去里面,实际上是class文件常量池
3.String中的一些常见方法
1)字符与字符串
//1字符数组变成字符串
char[] arr1={'a','b','c'};
String str=new String(arr1);
//2将部分字节数组的内容变成字符串
String hh=new String(arr1,1,3);
//3字符串变成数组
String str2="world";
char[] arr2=str2.toCharArray();
//4获取到固定位置的索引的字符
String dd=new String("lijiawei");
char ch=dd.charAt(1);
2)字节与字符串
//1字节数组转化成字符串
byte[] arr1={12,34,5,6,7};
String str=new String(arr1)
//2字符串转化成字节数组
String str1="abcdefgh";
byte[] arr=str1.getBytes();
/3忽略大小写的比较
String str1="abcdefg";
String str2="ABCDEFG";
System.out.println(str1.equalsIgnoreCase(str2));
//4 比较字符串的长度
String str3="abcdefg";
String str4="abcdef";
//str1>str2返回的是正数;str1==str2返回的是0;str1<str2返回的是负数
System.out.println(str1.compareTo(str2));
3)字符串的其他方法
//1字符串的替换
String str1="ababababababpppphhh";
String ret=str1.replace("ab","123");//这回创建一个新的对象
//替换首个指定字符的字符串
ret=str1.replaceFirst("ab","123");
System.out.println(ret);
//2字符串的截取
String str1="Hello";
String ret=str1.substring(1);//从一号位置开始进行截取,截取后面的字符串
System.out.println(ret);//打印出来的值是llo
ret=str1.substring(1,4);[1,4)从一号位置到四号位置进行字符串的截取
//3去掉字符串两边的空格,但是不可以去掉字符串中间的空格
String str1=" abcdef gh ";
String ret=str1.trim();
System.out.println(ret);
//4查找指定的字符串在原字符串的位置
String str1="abcdefg";
int index=str1.indexOf("abc");
int num=str1.indexOf("def");
System.out.println(index);
System.out.println(num);
//5查找目标字符串是否在源字符串之内
String str1="abcdef";
boolean flag=str1.contains("abcdef");
System.out.println(flag);//打印结果是true
4)字符串进行查找
//1从某个位置开始找
String str1="abcdefghabcdefgh";
int index=str1.indexOf("def",2);//从2号位置开始查询def所在的位置
System.out.println(index);//打印结果是3
//2从后面向前面找
index=str1.lastIndexOf("abc");
System.out.println(index);//打印结果是8
//3判断某个字符串是否以xx开头
String str="abcdef";
boolean flag=str.startsWith("ab");
System.out.println(flag);
//4判断某个字符串是否以指定的偏移量开始
String str="abcdefg";
boolean flag=str.startsWith("abc",0);
System.out.println(flag);
//5判断某个字符串是否以xx结尾
String str1="abcdefg";
boolean flag=str.endswith("abc");
System.out.println(flag);//false;
5)有关于字符串的拆分---返回值是一个字符串数组
1)String str1="abc de f";
String arr1[]=str1.split(" ",2);
for(String ret:arr1)
{
System.out.println(ret);
}
//如果split()后面加上了一个参数2,那么此时返回的字符串就会分成两组,一组是abc,一组是de f;
如果不加上2这个参数或者说压根就没有参数,此时就会默认分成三组,一组是abc,一组是de,一组是f;
2)String str1="name=zhangsan&age=19";
String[] arr1=str1.split("&");
for(String[] ret: arr1)
{
String[] ss= ret.split("=");
for(String sss:ss)
{
System.out.println(sss);
}
}
3)String str1="127.0.0.1";
String[] strings=str1.split("\\.");
//.号这个字符编译器是无法认清的,所以我们要通过/来进行转义,但是我们还需要对/来进行转义,所以要再加上一个/
for(String hh:strings)
{
System.out.println(hh);
}
}
}
4)字符"|","*","+",前面加上"\"
如果是"",里面就要写上\\
String str1="127*0*0*1";
String[] strings=str1.split("\\*",7);
//.号这个字符编译器是无法认清的,所以我们要通过/来进行转义,但是我们还需要对/来进行转义,所以要再加上一个/
for(String hh:strings)
{
System.out.println(hh);
}
}
5)str2="127\\0\\0\\1",这时候分割就要写四个\
String str2="127\\0\\0\\1";
String[] arr1=str2.split("\\\\");
for(String ret:arr1)
{
System.out.println(ret);
}
6)
String str1="java300 12&31#hello";
String[] strings=str1.split(" |&|#");
for(String str:strings)
{
System.out.println(str);
}
7) String str1="abcdef";
String str2=str1.toUpperCase();//将小写字母全部变成大写字母,同理str1.toLowerCase是把所有的的大写字母变成小写字母
System.out.println(str2);
8)判断字符串是否为空.isEmpty()方法
9)contat()方法,出字符串常量池
intern()方法,手动入池,表示最后拼接的对象不会进入到常量池里面,会new一个新的对象
String str1="hello".concat("1");
String str2="hello1";
System.out.println(str1==str2);//false
在这里面我们要注意String str1="";表示这个str1的引用指向一个空字符串,String str2=null,表示str2不会指向任何对象
3.StringBuilder与StringBuffer
1)String类与StringBuffer的类最大的区别就是String的内容无法进行修改,但是StringBuffer的内容是可以进行修改的,所以我们在频繁的修改字符串的时候优先考虑StringBuffer
StringBuilder stringBuilder=new StringBuilder("hello");
StringBuilder str=stringBuilder.append("world");
System.out.println(str==stringBuilder);
String str1="hello";
String str2="hello"+"world";
System.out.println(str1==str2);
2)String的拼接会产生大量的临时对象,所以我们是不可以循环进行拼接的,但是StringBuffer和StringBuilder会返回当前对象的引用
3)普通的String字符串拼接会被优化成StringBuilder
4) StringBuffer对象则代表一个字符序列可变的字符串,当一个StringBuffer被创建以后,通过StringBuffer提供的append()、insert()(将指定的字符集插入到指定位置)、reverse()、setCharAt(),delete(a,b)(删除指定位置区间的字符)等方法可以改变这个字符串对象的字符序列。一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString()方法将其转换为一个String对象。
5)StringBuffer是线程安全的,StringBuilder是线程不安全的