String类概念
String API
String类型字符串对象内存分析
StringBuilder和StringBuffer
String StringBuilder StringBuffer对比
字符串常量池
java.lang
String是一个用final修饰过的类,使用方式有两种
赋值一个字面量,字面量存放在字符串常量池中
String s=”abcde”;//指向的是字符串常量池中的字符串对象
调用String类的构造方法,会在堆区(非常量池)中创建一个字符串对象,每new一次,都会重新创建一个新的字符串对象
1)调用String类型的参数的构造方法:String s=new String(“abcde”).
2)调用char 数组类型参数的构造方法
3)调用byte类型数组的构造方法:通过使用平台的默认字符集解码将指定的字节数组来构造新的 String
。
4)调用byte类型数组的构造方法:通过使用指定的编码指定的字节数组来构造新的 String
package a_info; ? import java.io.UnsupportedEncodingException; ? public class Demo1 { //String类存放在java.lang包 //String类被final修饰,说明不能被继承 //private final char value[] //String类中存储的字符串,底层是字符数组 //被final修饰,不能进行修改,String也有不可变的特性 //学习API,就是学习类、包、属性、构造方法、方法 public static void main(String[] args) throws UnsupportedEncodingException { String str = "abc"; ?//"abc"存在常量池中,第一次使用时,需要在常量池中存入abc,将地址赋给str String str2 = "abc"; //在常量池中查找是否有abc,如果有,直接将abc的地址赋给str2 // System.out.println(str==str2); // String str3 = new String(); //声明没有内容的字符串对象 // System.out.println(str3); // String str4 = new String("abc"); // System.out.println(str==str4); // System.out.println(str.equals(str4)); ? // byte[] bytes2 = {97,98,99}; // String str8 = new String(bytes2); //以字节数组为参数,构造成字符串,没有指定编码,可能会出现乱码 // System.out.println(str8); String str5 = "早上好"; byte[] bytes = str5.getBytes("UTF-8"); String str6 = new String(bytes,"UTF-8"); //以字节数组和编码名称做为参数,构造成字符串,避免乱码 System.out.println(str6); } ? } ?
==和equals的区别?(重要)
等号比对的是两个字符串对象的地址信息,可以比对null对象 str==str2,str可以为null
equals:用途:比较字符串的内容,重写Object的方法
equals的比较过程:首先比较两个字符串对象的地址,如果地址一样直接返回true, 如果地址不一样,再比对字符串的内容,字符串内容一样返回true,不一样返回false,不能使用Null对象调用,str.equals(str2) .
实例
String str="abcde"; String str1="abcde"; String str2 = new String("abcde"); System.out.println(str.equals(str2));//true System.out.println(str==str1);//true System.out.println(str==str2);//false
String常见操作
public int length():非静态方法,获取字符串长度
//获得字符串的长度 int length = str.length(); System.out.println(length);
public char charAt(位置):返回某一个位置的字符,位置范围为:[0~字符串长度-1]
//char charAt(int index) //根据参数index的位置返回字符串中该位置的字符 char c = str.charAt(0); System.out.println(c);
public int indexOf(字符|字符串):返回某一个字符或者字符串第一次出现的的位置,找不到返回-1
public int indexOf(字符|字符串,开始位置):从指定位置开始找,返回某一个字符或者字符串第一次出现的的位置,找不到返回-1
//int indexOf(int ch) //找出ch数字对应字符在原串中第一次出现的位置 // int i = str.indexOf(97); // System.out.println(i); //int indexOf(int ch,int fromIndex) // 从fromIndex找出ch数字对应字符在原串中第一次出现的位置 //int indexOf(String str) //找出str在原串中第一次出现的位置 //int indexOf(int ch,int fromIndex) // 从fromIndex找出str在原串中第一次出现的位置 //如果找不到,返回-1
public int lastIndexOf(字符|字符串):从后向前找第一次出现的位置
//获得文件的名字 int lastIndexOf = filename.lastIndexOf('.'); String fname = filename.substring(0, lastIndexOf); System.out.println(fname);
public String substring(起始位置):从开始位置截取字符串
public String substring(起始位置,结束位置):截取字符串,包含起始位置,但是不包含结束位置
//String substring(int beginIndex) 从beginIndex截取到字符串末尾,并将截取后的结果返回 //String substring(int beginIndex, int endIndex); 从beginIndex截取到endIndex(不包含endIndex),并将截取后的结果返回
public boolean equals(Object str):比较两个字符串的内容
public String toUpperCase():将一个字符串转换为纯大写
public String toLowerCase():将一个字符串转换为纯小写
public boolean equalsIgnoreCase(另一个字符串):忽略大小写进行比较
String str = "This is a student."; // public String toUpperCase():将一个字符串转换为纯大小 System.out.println(str.toUpperCase()); // public String toLowerCase():将一个字符串转换为纯小写 System.out.println(str.toLowerCase()); // public boolean equalsIgnoreCase(另一个字符串):忽略大小写进行比较 System.out.println(str.equalsIgnoreCase("this is a student."));
public String concat(另一个字符串):连接字符串,另一个字符串长度不为0的时候,连接的结果为新创建了一个字符串对象,反之,返回的是当前对象
public String replace(char oldCh, char newCh):将字符串的字符oldCh替换为字符串newCh
public int compareTo(Stirng str):
//比较两个字符串,如果完全一样,则返回0 //如果长度不相同,返回长度差 //如果长度相同,字符不同,返回第一个不同的字符差
public boolean startsWith(String prefix):是否以某个字符串开始
public boolean endsWith(String suffix):是否以某个字符串结尾
String[] files = {"abc.txt","abb.jpg","bcc.doc","ccc.txt"}; // public boolean startsWith(String prefix):是否以某个字符串开始 //1、找出以a开头的文件 for(String file:files) { if(file.startsWith("a")) { System.out.println(file); } } // public boolean endsWith(String suffix):是否以某个字符串结尾 //2、找出以.txt为结尾的文件 for(String file:files) { if(file.endsWith(".txt")) { System.out.println(file); } }
public boolean contains(String str):是否包含某一个字符串
//3、找出文件名中有c的文件 for(String file:files) { if(file.contains("c")) { System.out.println(file); } }
public String [] split(String str):对一个字符串按照指定字符做分割
//按照参数将原字符串分割成若干份 //"name:andy,age:18,score:80" String stuStr = "name:andy,age:18,score:80"; //{"name:andy","age:18","score:80"} String[] strings = stuStr.split(","); for (String string : strings) { System.out.println(string); }
public byte [] getBytes():返回一个字符串的字节数组形式,数组中存放的是字符串中每个字符的编码,编码方式默认为平台默认编码
public byte [] getBytes(字符集编码):返回一个字符串的字节数组形式,数组中存放的是字符串中每个字符的编码,编码方式默认为平台默认编码
public String toString():返回当前字符串对象
public char[] toCharArray():将一个字符串转换字符数组形式
static valueOf(各种数据类型的参数)
字符串应用
实例一:判断一个字符串在另一个字符串中出现的次数
public static int countTimes(String source,String searchStr) { int times = 0; int from = 0; int index = source.indexOf(searchStr,from); while(index>-1) { times++; from = index + 1; index = source.indexOf(searchStr,from); } return times; }
实例二:判断字符在一个字符串中有没有重复
实例三:遍历字符串
实例四:各种转换
将字符数组转换为字符串的两种方式
方式一
char cs[]={'a','b','c'}; String str=String.valueOf(cs);//"abc"
方式二:
char cs[]={'a','b','c'}; String str = new String(cs);
将字符串转换为字符数组的方式
String str="abcde";//将一个字符串转换为char类型的数组 char cs[]=str.toCharArray();
实例五:
package b_api; public class App5 { public static void main(String[] args) { String str2 = "tHis iS A sTuDENT!"; //将这个英文句子每个单词首字母大写,其他字母全小写 //1、将这个英文句子全转小写 //this is a student! str2 = str2.toLowerCase(); //2、获得字符串的字符数组 char[] charArray = str2.toCharArray(); //3、循环遍历第0位和空格后面的位置,将字符数组中对应的字符转成大写 for (int i = 0; i < charArray.length; i++) { if(i==0) { charArray[0] = (char)(charArray[0]-('a'-'A')); } if(charArray[i]==' ') { charArray[i+1] = (char)(charArray[i+1]-('a'-'A')); } } //4、将字符数组转回字符串 str2 = new String(charArray); System.out.println(str2); } }
两种创建字符串对象的方式的区别
String str=”abcde”;//str指向的是常量池中的字符串对象,常量池中没有重复的字符串对象
String str1=”abcde”;
sout(str==str1)//true
String str=new String(“abcde”);//str指向堆里面开辟的新空间
String str1=new String(“abcde”)
sout(str==str1)//false
String str1=new String(“abcde”)
注意:以下代码创建了几个字符串对象
String str1=new String(“abcde”)
如果字符串常量池中没有abcde,就是两个,如果有,就是1个,
如果是两个。则两个字符串对象的value属性的属性值是一样,value属性存放的是字符串的内容,体现为char类型的数组,
String类型的底层存储结构 String类型的字符串的底层结构,是一个字符类型的数组,并且用final修饰过,String类型的对象有一个重要的属性value,value中存放的是字符数组的地址信息,实际的字符串的内容子啊字符数组中存放
3.String不可变字符串
不可变的现象
String类型的字符串,不可改变,每次对String类型的字符串对象做修改拼接等操作的时候,都会形成一个新的字符串对象,原有字符串对象的内容不可改变
如何做到不可变的
底层char []value,用final修饰过,只能被赋值一次,只能指向一个字符数组,如果要更改,只能创建一个新的String类型的对象。
应用场景:如果在某一次操作中,频繁对字符串做修改拼接操作,不适合用String,因为每次修改拼接会形成一个新的字符串对象, 如果只是做遍历,String非常合适
StringBuffer和StringBuilder的区别: StringBuffer线程安全,效率低,StringBuilder线程不安全,但是效率高
String和StringBuffer或者StringBuilder的区别: String为不可变字符串,适合做遍历,不适合频繁拼接修改 StringBuffer或者String和StringBuffer或者StringBuilder的区别可变
可变性分析
现象
StringBuffer(StringBuilder)为可变字符串,每次修改拼接不会产生新的StringBuffer(StringBuilder)对象,在原有字符串的基础上做更改,底层有可能产生新的char类型的数组
如果做到可变
底层的的结构为char [] value,没有用final修饰,可以被多次赋值,所以没有必要再创建新的StringBuffer类型的对象
如果缓冲区满了,会怎么样
为什么要带缓冲区:为了减少频繁扩容的频率,缓冲区放满的时候要进行扩容,扩容的公value.length*2+2.
应用场景
适合做频繁拼接修改的场景
String:对形参的任何操作不会影响实参 StringBuffer:对形参的操作可能会影响实参,前提是形参在操作之前没有指向新的对象。
StringBuffer常用API
StringBuffer str=new StringBuffer();//缓冲区的默认长度为16 StringBuffer str=new StringBuffer(5);//缓冲区的默认长度就是5 StringBuffer str=new StringBuffer("abcde");//缓冲区的默认长度为字符串的长度+16 System.out.println("字符串内容的长度"+str.length()); System.out.println("缓冲区长度(本质就是底层字符数组的长度)"+str.capacity()); StringBuffer sb=new StringBuffer("abcde"); sb.setCharAt(0, 'A'); sb.append(true); sb.append(1); sb.insert(1, "hello");//指定位置插入 sb.reverse();//翻转字符串 //将StringBuffer装换为String String str=sb.toString();
StringBuffer|StringBuilder和String之间的相互转换
String转换为StringBuffer|StringBuilde
String str = "abcde"; StringBuffer sb = new StringBuffer(str);//构造方法参数为要转换的字符串
StringBuffer转换为String
StringBuffer sb = new StringBuffer("abcde"); String str = sb.toString();
相同点:都能表示字符串,底层实现都是char类型的数组
不同点:
String类型为不可变字符串,底层的value属性用final修饰过,只能被赋值一次,只能指向一个字符数组。做修改追加的操作的时候,会形成新的字符串(String)对象,所以不太适合频繁做修改,适合遍历
StringBuffer和StringBuilder,可变字符串,底层value属性没有用final修饰过,可以被多次赋值,可以在不同时间指向多个字符数组,修改追加等操作的时候,不能形成的新的StringBuffer|StirngBuilder类型的对象,适合做修改,
StringBuffer线程安全,StringBuilder线程不安全
减少频繁创建销毁对象的频率,提高了单个对象的利用率
什么样的字符串会放在常量池中
字符串的字面量
用+连接的结果,但是前提是+两边都是字面量或者是常量(final)