基本
我们先来看一下String在Jdk中的定义
-
我们发现这是一个String类被finl进行修饰了,name就可以知道String类型对象被声明之后,将不可改变。
另外,我们可以看到String类实际上底层就是字符数组!
public class StringTest{
public static void main(String[] args){
String word = "abc";//刚才所说的不可改变是“abc”对象不可改变,但是word可以重新引用其他对象
}
}
- 由于String类型是经常使用的一个类,所以在jvm中的方法区中存在一个“字符串常量池”,所有在java中使用”“双引号括起来的字符串,都会被存储到方法区的字符串常量池中。
- 在程序的执行过程中,如果用到了某一个字符串,比如“abc”,就会去字符串常量池中进行一个查找,如果找到就直接引用,没有找到就进行创建。
@Test
public void test(){
String word = "aaa";
String word2 = "aaa";
System.out.println(word == word2);//输出true
//注意比较字符串的时候必须用equals方法,因为==不一定全是true
String word3 = new String("aaa");
System.out.println(word == word3);//输出false
//这种new出来的String是在jvm的堆中开辟空间,内存地址就不一样了
}
问题:以下程序执行完毕后会在字符串常量池中创建几个字符串对象?
String a = "aaa";
String b ="bbb";
String c = a + b;
三个!还是因为字符串对象不可变!a+b只能重新创建一个字符串对象!
创建字符串对象的两种区别
String a = "aaa";
String b = new String("aaa");
//第一种方法只在方法区中的字符串常量池中进行一个创建,第二种会在堆中进行创建,并且在字符串常量池中也进行创建,推荐使用第一钟表馆,因为这样消耗内存资源少
面试题
public StringTest{
public static void main(String[] args){
//判断以下会创建几个对象?
String a = new String("aaa");
String b = new String("aaa");
//答:三个,在堆中有两个,在方法区中的字符串常量池中共用一个!
}
}
注意的问题
使用String的时候我们应该注意,尽量不要使用字符串做频繁的拼接操作,因为字符串一旦创建不可改变,要是频繁的拼接,就会在字符串常量池中进行大量的创建对象,会给垃圾回收带来问题。
常用方法
构造方法
@Test
public void test(){
//1.
String s1 = "aba" ;
//2.
String s2 = new String("abc") ;
//3.
byte[] bytes = {97,98,99,100};
String s3 = new String (bytes);
System.out.println(s3); //abcd String已经重写 了object中的tostring
//4.
String s4 = new String (bytes,1,2) ;
System.out.println(s4); //bc
//5.
char[] cl = {'我','是','中','国','人'};
String s5 = new String (cl) ;
System.out .println(s5) ; //我是中国人
//6.
String s6 = new String (cl,2,2) ;
System.out.println(s6) ; //中 国
}
普通方法
@Test
public void test(){
//1、char charAt(int index),返回指定索引处的char值
char c1 = "shaoZhaoWei".charAt(1);
System.out.println(c1);
//2、boolean endsWith(String suffix),测试此字符串是否以指定后缀结束
System.out.println("www.szw.com".endsWith(".com"));//返回true
//3、boolean equalsIgnoreCase(String anotherString) 比较两个字符串但是忽略大小写
System.out.println("abc".equalsIgnoreCase("abC"));//返回true
//4、byte[] getBytes() 将字符串装换为字符数组
byte[] bytes = "abc".getBytes();
for (int i = 0; i < bytes.length; i++) {
System.out.print(bytes[i]);//输出的是abc所对应的阿斯克码
}
System.out.println();
//5、int index of 返回子字符串在字符串中第一次出现的索引值
System.out.println("szw.szw.com".indexOf("s",1));//后面的参数是跟的下标开始值
//6、lastIndex0f(String str,int fromIndex)
System.out.println("aaaazzzzs".lastIndexOf("s",4));//是从z开始向前反向搜索,z以后的就不管了
//7、length(),在数组中是属性,在string中是方法
System.out.println("aaaa".length());
//8、替换replaceAll
System.out.println("szwabc".replaceAll("szw","SZW"));//这个程序生成了4个字符串
//9、字符串分割成数组
String myTime = "2020,1,10";
String[] myTimeA = myTime.split(",");
System.out.println(myTimeA.length);
for (int i = 0; i < myTimeA.length; i++) {
System.out.print(myTimeA[i]);
}
System.out.println();
//10、startWith 是否以指定字符串开始
System.out.println("/szw/10".startsWith("/szw"));
//11、String substring(int beginIndex,int endIndex),截取字符串,包括起始索引,不包括结束索引
System.out.println("abcdef".substring(3,5));
//12、char[] toCharArray();转换成一个字符串数组
//13、toUpperCase()转换成大写
System.out.println("abc".toUpperCase());
//14、toLowerCase()转换成小写
System.out.println("ABV".toLowerCase());
//15、trim() 去除首尾空格
System.out.println(" TE s t ".trim());
//16、value0f
Object ss = 11;
System.out.println(String.valueOf(ss));
}
StringBuffer和StringBuilder
这两个是什么?
是一个字符串缓冲区
工作原理
预先在内存中申请一块空间,以容纳字符序列,如果预留空间不够用,就会自动扩容,以容纳更多的字符序列,我们来看看那StringBuffer的底层!
我们继续看一下他的父类
而在Stringbuffer写了16,就代表这个字符串缓冲区默认的大小就是16.
StringBuffer、StringBuilder和String的不同
String是不可变的,存储在方法区的字符串常量池中。StringBuffer的底层是一个char数组,该数组可以通过拷贝去自动扩容,或者在使用的时候,根据自己的判断给char数组进行初始化大小(这样就算优化StringBuffer)
//方法:
sb.append();//向Stringbuffer中添加
String与Stringbuffer与StringBuilder区别
String是不可变的字符序列,并且线程不安全。少量数据的时候可以使用。
StringBuffer是线程安全的,但是效率低,多线程下操作大量数据使用。
StringBuilder是线程不安全的,效率高,单线程下操作大量数据使用。