java常用类-字符串
一、String类及常用方法
String :字符串,使用一对""引起来表示。
1.理解String的不可变性
(1)String实现了Serializable接口:表示字符串是支持序列化的
(2)实现了Comparable接口:可以比较大小
(3)String内部定义了final char[] value用于存储字符串数组
(4)代表不可变的字符序列。
体现:1.当对字符串重新赋值时,不能在原有的地址存储空间内赋值,而
是新建一个地址存储空间
2.当对现有的字符串进行连接操作会也需要重新指定区域赋值,不能
使用原有的value(字符串长度)进行赋值
3.当调用String的replace方法修改指定字符或字符串之后,也需要
重新指定内存区域
点击查看代码
package com.Tang.StringDay01;
import org.junit.Test;
public class StringTest {
@Test
public void test1(){
String s1 = "abc";//字面量的定义方式,String为一个类,对象的赋值可以像基本数据类型一样去赋值
String s2 = "abc";
// s1 = "hello";
System.out.println(s1 == s2);//比较两个对象的地址值是否相同
System.out.println(s1);
System.out.println(s2);
System.out.println("***************");
String s3="abc";
s3 += "def";
System.out.println(s3);//abcdef
System.out.println(s2);
System.out.println("***************");
String s4 = "abc";
String s5 = s4.replace('a', 'm');
System.out.println(s4);//abc
System.out.println(s5);//mbc
}
}
2.不同实例化方式的对比
点击查看代码
package com.Tang.StringDay01;
import org.junit.Test;
public class StringTest {
/*
String 的实例化方式:
方式一:通过字面量定义的方式
方式二:通过new +构造器的方式
面试题:String s = new String("abc")方式创建对象,在内存中创建了几个对象?
两个:一个堆空间中new结构,另一个是char[]对应的常量池中的数据:"abc"
*/
@Test
public void test2(){
//通过字面量定义的方式:此时的s1和s2的数据javaee声明在方法区中的字符串常量池中
String s1 = "javaEE";
String s2 = "javaEE";
//通过new +构造器的方式:此时的s3 和 s4 保存的地址值,是数据在堆空间中开辟空间以后对应的地址值
String s3 = new String("javaEE");
String s4 = new String("javaEE");
System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//false
System.out.println(s1 == s4);//false
System.out.println(s3 == s4);//false
System.out.println("*********************");
Person tom = new Person("Tom", 23);
Person tom1 = new Person("Tom", 23);
System.out.println(tom.name.equals(tom1.name));//true
System.out.println(tom.name == tom1.name);//true
System.out.println(tom.age == tom1.age);//true
System.out.println("****************");
tom.name="jerry";
//虽然tom和tom1在常量池中属于一个存储地址,
//但是当tom改变值的时候并不会影响tom1的值,而是新开辟一个内存空间
System.out.println(tom1.name);
}
3.不同拼接方式的操作
在堆中开辟的空间不同对象占用不同的地址空间,但是在常量池中只要内容相同就属于一个地址空间
点击查看代码
@Test
public void test3(){
String s1 ="javaEE";
String s2 = "hadoop";
//s3和s4
String s3 = "javaEEhadoop";
String s4 = "javaEE"+"hadoop";
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;
System.out.println(s3 == s4);//true
System.out.println(s3 == s5);//false
System.out.println(s3 == s6);//false
System.out.println(s5 == s6);//false
System.out.println(s5 == s7);//false
System.out.println(s6 == s7);//false
String s8 = s5.intern();//返回得到的s8使用的是常量池中已经存在的"javaEEhadoop"
System.out.println(s3 == s8);//true
}
4.常用的方法
(1)第一部分
每一个方法测试如下代码
点击查看代码
package com.Tang.StringDay01;
import org.junit.Test;
import java.util.Locale;
public class StringMethodTest {
@Test
public void test1(){
String s1 = "HelloWorld";
System.out.println(s1.length());
System.out.println("==================");
System.out.println(s1.charAt(0));//H
System.out.println(s1.charAt(9));//d
System.out.println(s1.isEmpty());//s1非空所以是false
System.out.println("==================");
String s2 = s1.toLowerCase();//s1.toUpperCase()将小写转为大写
System.out.println(s1);//s1是不可变的任然为原来的字符串
System.out.println(s2);//将大写改成小写以后的字符串
System.out.println("==================");
String s3 = " he llo wo rld ";
String s4 = s3.trim();
System.out.println("----" + s3 + "------");
System.out.println("----" + s4 + "------");
System.out.println("==================");
String s5 = "helloworld";
System.out.println(s1.equals(s5));//false
//忽略大小写
System.out.println(s1.equalsIgnoreCase(s5));//true
System.out.println("==================");
String s6 = "acd";
String s7 = "aec";
//因为c的为99,e为101二者相减为负值,表示第一个串比第二个串小
System.out.println(s6.compareTo(s7));
System.out.println("==================");
String s8 = "TangwuQiang";
String s9 =s8.substring(4);//去掉字符串前四个字符
System.out.println(s8);
System.out.println(s9);
String s10 = s8.substring(4,6);//截取下标为4和5的两个字符,区间为左闭右开
System.out.println(s10);
}
}
(2)第二部分
每一方法测试代码如下:
点击查看代码
public void test2(){
String s1 = "helloworld";
System.out.println(s1.endsWith("ld"));//看字符串是否是以ld结尾
System.out.println(s1.startsWith("He"));//看字符串是否是以he开头
System.out.println(s1.startsWith("ll",2));//看字符串从下标为2开始是否是以ll开头
System.out.println("==================");
String s2 = "wor";
System.out.println(s1.contains(s2));//判断s1里面是否包含s2
System.out.println("==================");
System.out.println(s1.indexOf("lo"));//判断lo子串在s1中是否存在且返回在字符串中第一次出现的位置下标,若不存在返回-1
System.out.println(s1.indexOf("lo", 5));//从字符串下标为5的位置开始寻找是否包含lo子串,可以用来
System.out.println("==================");
System.out.println(s1.lastIndexOf("or"));//从右往左找,返回在字符串中下标的值还是从左往右的顺序
System.out.println(s1.lastIndexOf("or", 6));//从下标为6的位置开始,往左找子串or
}
(3)第三部分
测试代码如下:
点击查看代码
@Test
public void test3(){
String s1 = "菜鸟一枚";
System.out.println(s1.replace('菜', '水'));
}
5.String与基本数据类型、包装类之间的转换
点击查看代码
@Test
public void test4(){
String s1 = "123";
//int num = (int)str1;只有具有继承关系的才可以强转
int num = Integer.parseInt(s1);//利用包装类将String强转为整形
System.out.println(num);
String s2 = String.valueOf(num);//调用String重载的valueof将整形数字转为字符串
String s3 = num + "";//也可以将整形num转为字符串类型
}
点击查看代码
@Test
public void test5(){
String s1 = "abc123";
//String--->char[]调用String的toCharArray
char [] charArray = s1.toCharArray();
for (int i = 0; i <charArray.length ; i++) {
System.out.println(charArray[i]);
}
//char[]--->String调用String的构造器
char [] arr = new char[]{'h','e','l','l','o'};
String s2 = new String(arr);
System.out.println(arr);
}
7.String与byte[]之间的转换
点击查看代码
@Test
public void test6() throws UnsupportedEncodingException {
String s1 = "abc123唐";//在utf - 8模式下,一个汉字占三位
//tring--->byte[]调用String的getBytes()
byte[] bytes = s1.getBytes();//使用默认的字符集进行编码
System.out.println(Arrays.toString(bytes));
byte[] gbks = s1.getBytes("gbk");//使用gbk编码可能不对,所以要抛出一个异常
System.out.println(Arrays.toString(gbks));//使用gbk字符集进行编码,一个汉字占两位
System.out.println("=======================");
//Byte[]--->String调用String的构造器
String s = new String(bytes);//使用默认的字符集进行解码
System.out.println(s);
String s2 = new String(gbks);//gbks使用的是gbk编码的,解码也应该使用gbk解码
System.out.println(s2);//这里的解码方式是utf-8与编码字符集不一致所以会出现乱码
String s3 = new String(gbks, "gbk");
System.out.println(s3);//编码和解码集一致,因此不会出现乱码
}
二、StringBuffer、StringBuilder
1.String、StringBuffer、StringBuilder区别
String:不可变的字符序列,底层使用char []存储
StringBuffer:可变的字符序列:线程安全的(源码中每一个方法前有synchronized),效率低,底层使用char []存储;
StringBuilder:可变的字符序列:jdk 5.0新增的,线程不安全的(源码方法中没有synchronized),效率高,底层使用char []存储
点击查看代码
@Test
public void test(){
StringBuffer as = new StringBuffer("abc");
as.setCharAt(0,'m');//在原有的地址块中修改
System.out.println(as);//输出mbc
}
2.源码分析:
(1) String str = new String()//在底层源码中Byte[] vaue= new byte[0]
(2)String str1 = new String("abc");//Byte[] vaue= new byte[]{'a','b','c'};
(3)无参构造源码分析:StringBuffer s1 = new StringBuffer();//相当于在底层创建了一个长度为16的数组,
s1.append('a');//value[0] = 'a';
s1.append('b');//value[1] = 'b';
s1.append('c');//value[2] = 'c';
(4)有参构造源码分析 StringBuffer s2 = new StringBuffer("abc")//在底层相当于 Byte[] vaue= new byte["abc".length()+16],就是在原有字符串长度的基础上再加上16。
(5)扩容问题:如果要添加的数据底层数组装不下了,那就需要扩容底层的数组,默认情况下啊扩容为原来的2倍+2,同时将原有数组中的元素复制到新的数组中
2.StringBuffer类常用的方法
每一方法的测试代码如下
点击查看代码
@Test
public void test2(){
StringBuffer s1 = new StringBuffer("abc");
s1.append(46);//末尾添加字符
s1.append('1').append('4');//可以连着点append
System.out.println(s1);
System.out.println("===================");
s1.delete(2,4);//左闭右开
System.out.println(s1);
System.out.println("===================");
s1.replace(0,2,"YM");//将前两个字符体换为YM
System.out.println(s1);
System.out.println("===================");
s1.insert(0,"Twq8023");//在第一个字符前插入Twq8023
System.out.println(s1);
System.out.println("===================");
System.out.println(s1.reverse());//将s1反转
System.out.println("===================");
String substring = s1.substring(1, 3);//截取串中下标为1和2的两个字符
System.out.println(s1);
System.out.println(substring);
}
3.方法重点总结:
(1)增:append(XXX);
(2)删:delete(int start, int end);//删除下标为start到end-1之间的所有字符
(3)改:setCharAt(int n, char ch)//只修改一个字符 / replace(int start ,int end , String str)//将下标为start到end-1之间的字符修改为str
(4)查:charAt(int n)//查询下标为n的字符
(5)插:insert(int offset, xxx)//在下标为offset的字符前插入xxx
(6)长度:length();
三、经典例题
1.将一个给定的字符串从指定下标开始位置到结束位置的字符反转如将串"abcdefg"的下标为2到4之间的字符反转得到 abedcfg;
实现代码如下:
点击查看代码
//反转方式一:
public String reverse(String str,int startIndex,int endIndex){
char [] arr = str.toCharArray();
for (int i = startIndex,j=endIndex; i <j ; i++,j--) {
char temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
return new String(arr);
}
//反转方式二:使用String的拼接
public String reverse1(String str, int startIndex,int endIndex){
String strReverse = str.substring(0,startIndex);//第一部分
for (int i = endIndex; i >=startIndex ; i--) {//第二部分
strReverse += str.charAt(i);
}
strReverse += str.substring(endIndex+1);//第三部分
return strReverse;
}
//反转方式三:使用StringBffer / stringBuiler来替换String
public String reverse2(String str, int startIndex,int endIndex){
StringBuilder builder = new StringBuilder(str.length());//为防止初始16不够长,直接将初始长度定义为与字符串一样长
builder.append(str.substring(0,startIndex));//第一部分
for (int i = endIndex; i >=startIndex ; i--){//第二部分
builder.append(str.charAt(i));
}
builder.append(str.substring(endIndex+1));
return builder.toString();
}
@Test
public void test1(){
String str = "abcdefg";
String r1 = reverse(str,2,4);
String r2 = reverse1(str ,2,4);
System.out.println(r1);
System.out.println(r2);
String r3 = reverse2(str,2,4);
System.out.println(r3);
}
2.获取一个字符串在另一个字符串中出现的次数比如:获取“ab”在“abkkacdkabkebfkabkskab”中出现的次数,答案:4
点击查看代码
/**
*判断subStr在mainStr中出现的次数
* @param mainStr:主串
* @param subStr:
* @return
*/
public int getCount(String mainStr,String subStr){
int mainLength = mainStr.length();
int subLength = subStr.length();
int count = 0;
int index;
int index1 = 0;
if(mainLength>subLength){
// while((index = mainStr.indexOf(subStr)) != -1){
// count ++;
// mainStr = mainStr.substring(index + subLength);
// }
//改进;若找到subStr之后每次从index1+子串的长度处查找subStr
while((index1 = mainStr.indexOf(subStr,index1)) != -1){
count ++;
index1 +=subStr.length();
}
}
return count;
}
@Test
public void test2(){
String sbuStr = "ab";
String mainStr = "abkkacdkaabkebfkabkskab";
int count = getCount(mainStr, sbuStr);
System.out.println(count);
}