一)前置知识回顾:
字符串中的库函数,基本上只要对原来的字符串进行修改,基本上返回的都是一个新的对象
String s1=new String("hello"); String s2=new String("world"); String s3=s1;
二)下列程序的输出结果是:输出good和gbc
public class Task { String str=new String("good"); char[] ch={'a','b','c'}; public static void main(String[] args) { Task task=new Task(); task.change(task.str,task.ch); System.out.println(task.str); System.out.println(task.ch); } public void change(String string,char[] ch){ string="testOK"; ch[0]='g'; } }
1)当没有调用这个change方法之前,我们的函数的内存布局是这样子的:
2)当我们进行调用这个函数的时候,用形参来进行接受的时候,没有进入到方法之前:
3)进行接收到的形参会在栈上面开辟一块空间,此时string就指向了之前咱们对上面的String对象,咱们的形参的char[]数组指向的是堆中的0X100
4)进入到方法之后,因为形参的ch和实参的ch都指向同一块内存地址空间,所以形参可以直接根据引用,来进行修改数组的第一块元素位置改成了g
5)但是此时的string指向了一个新的字符串,所以它指向的字符串对象发生了改变,里面的引用所指向的地址也发生了改变
这就是整个内存变化图,由此可知str引用变量里面所指向的对象的地址并没有发生改变,不是说传递引用就一定可以改变原来的值, 而是说你拿着这个引用都做了一些啥样的事情
String中的一些常见方法
1)字符与字符串
1)public String(char value[])属于构造方法,将字符数组的内容变成字符串
2)public String(char[] value,int offset,int count)属于构造方法,将字符数组的部分内容变成字符串
3)public char charAt(int index)获取指定索引位置的字符
String str="HelloWorld"; for(int i=0;i<str.length();i++){ System.out.print(str.charAt(i)); } //HelloWorld
4)public char[] toCharArray()将字符串变成字符数组返回
String str="HelloWorld"; char[] values=str.toCharArray(); System.out.println(Arrays.toString(values)); //[H, e, l, l, o, W, o, r, l, d]
5)返回格式化字符串
String str=String.format("%s %s 我是中国人","我想飞","我想要找一个好工作"); System.out.println(str);
//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);
//判断是否是数字字符还有一种方法
char ch='0';
boolean flag=Character.isDigit(ch);
if(flag==false)
{
System.out.println("不是数字字符");
}else{
System.out.println("是数字字符");
}
//判断这个字符是不是字母
char ch='a';
System.out.println(Character.isAlphabetic(ch));
2)字节与字符串
1)public String(byte[] bytes[]):将字节数转化成字符串
2)public String(byte[],int offset,int length)将字节数组中的内容转化成字符串
3)public byte[] getBytes();将字符串以数组的方式来进行返回
4)public byte[] getBytes(String charsetName) throws UnsupportedException 编码转换处理
byte[] 是把String按照一个字节一个字节的来进行处理,这种情况下适合在网络情况下进行传输,数据存储的场景下进行使用,更适合用于二进制数据来进行操作
char[]是把String按照一个字符一个字符的来进行处理,更适合针对文本数据来进行操作,尤其是包含中文
//1字节数组转化成字符串
byte[] arr1={12,34,5,6,7};
String str=new String(arr1)
//2字符串转化成字节数组
String str1="abcdefgh";
byte[] arr=str1.getBytes();
3)字符串的其他方法
1)比较内容:equals()方法,是一种真假类型的比较,在Object的equals默认是比较的是地址
1.2)调用equals方法的时候,先看看两个对象的地址是否相同,是否指向同一个对象,相同返回true,也就是说判断他们是否指向同一个对象
1.3)在进行判断这两个对象的类型是否是相同的(防止你写了一个字符串引用和数组的引用来进行比较),instance of是判断是否是同一种类型,就是进行判断anObject是否是String类型的对象
1.4)如果说它们的类型相同,把形参的Object类型转化成字符串类型(将他进行向下转型转化成String类型的对象),再次比较它们的长度,长度不同,直接返回false
1.5)最后再循环进行比较他们对应字符的相同性,如果有一个对应的字符不相同,直接返回false
2)忽略大小写的比较ASCIl码值
String str1="abcdefg"; String str2="ABCDEFG"; System.out.println(str1.equalsIgnoreCase(str2));//打印true
3)还有忽略大小写比较字符串是否相等
String str1="hello"; String str2="Hello"; System.out.println(str1.equals(str2));//false System.out.println(str1.equalsIgnoreCase(str2));//true
4)比较字符串的长度:实现comparable接口,重写compareTo方法
1)如果第一个字符和参数的第一个字符不等,结束比较,返回第一个字符的ASCII码差值。
2)如果第一个字符和参数的第一个字符相等,则以第二个字符和参数的第二个字符做比较,以此类推,直至不等为止,返回该字符的ASCII码差值。
3)如果两个字符串不一样长,可对应字符又完全一样,则返回两个字符串的长度差值。
String str3="abcdefg"; String str4="abcdef"; //str1>str2返回的是正数;str1==str2返回的是0;str1<str2返回的是负数 System.out.println(str1.compareTo(str2));//String重写CompareTo方法
public int compareTo(String anotherString) { int len1 = value.length;//先进行获取当前this的字符串的大小 int len2 = anotherString.value.length;//在进行获取到传入的参数的字符串的大小 int lim = Math.min(len1, len2);//获取长度的最小值 char v1[] = value; char v2[] = anotherString.value; int k = 0; while (k < lim) { char c1 = v1[k]; char c2 = v2[k]; if (c1 != c2) { return c1 - c2; } k++; } return len1 - len2; }
1)public boolean contains(CharSequence s),判断一个子字符串是否存在,因为本质上String实现了CharSequence接口,只要实现了这个接口,那么数据类型都可以用CharSequence来进行接收
2)public int indexOf(String str)
从头开始进行查找指定字符串的位置,查到了就返回位置的开始索引,查不到就返回-1;
3)public int indexOf(String str,int fromindex)从指定位置开始查找字符串的位置
4)public int LastindexOf(String str)从后向前查找子字符串位置
5)public int LastindexOf(String str,int index)从指定位置从后向前进行查找,找到第一个字符的从前向后的索引位置
6)public boolean startWith(String prefix)是否已指定字符串开头
7)public boolean ensEith(String prefix)是否已指定字符串进行开头
String str="abcabcdef"; System.out.println(str.indexOf("a"));//从头开始找,遇到第一个就结束--->0 System.out.println(str.indexOf('d', 4));//从指定位置开始向后找System.out.println(str.indexOf("abc"));//从前向后开始进行查找0 System.out.println("=============================="); System.out.println(str.lastIndexOf('c'));5 System.out.println(str.lastIndexOf('b'));4 System.out.println(str.lastIndexOf("abc"));3
public static void main(String[] args) { //运行时的命令行参数,命令行参数会放在args数组里面 for(int i=0;i<args.length;i++){ System.out.println(args[i]); } }
4)字符串的替换:这里面都是默认创建了一个新的String
1)public String replaceAll(String regex,String replacement)替换指定的所有内容
2)public String replaceFirst(String regex,String replacement)替换首个内容
3)public String replace(char ch1,char ch2)将指定字符替换成指定字符,如果ch1=ch2那么直接返回原来的字符串
4)public String replace(String str1,String str2),构成了重载
//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
5)字符串进行查找
//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;
6)有关于字符串的拆分---返回值是一个字符串数组
1)public String[] split(String regex),将字符串全部进行拆分
2)public String[] split(String regex,int limit),将字符串进行部分拆分,该数组长度就是limit极限,不会进行均匀分割
1)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); } } arr1[0]="name=zhangsan"; arr1[1]="age=19";
2)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;
3)String str1="127.0.0.1"; String[] strings=str1.split("\\."); .号这个字符编译器是无法认清的,所以我们要通过/来进行转义,但是我们还需要对\来进行转义,所以要再加上一个\ for(String hh:strings) { System.out.println(hh); } } }
注意事项:
1)字符"|","*","+","",前面加上"\\"
String str1="127*0*0*1"; String[] strings=str1.split("\\*",7); .号这个字符编译器是无法认清的,所以我们要通过/来进行转义,但是我们还需要对/来进行转义,所以要再加上一个/ for(String hh:strings) { System.out.println(hh); } }
2)如果是"",里面就要写上\\3)如果是一个字符串有多个分隔符,那么我们可以使用|来进行分割
String str1="java300 12&31#hello"; String[] strings=str1.split(" |&|#"); for(String str:strings) { System.out.println(str); } //这里面的的分隔符有很多,包括空格,&,#我们可以使用|来进行分割
4)分割\\要写四个\\\\
String str1="1\\2\\3\\4\\5"; String[] strings=str1.split("\\\\"); for(String s:strings) { System.out.println(s); }
String string="123&8989=90&AAA bbb ccc&BBBB"; String[] strings=string.split(" |=|&"); System.out.println(Arrays.toString(strings)); [123, 8989, 90, AAA, bbb, ccc, BBBB]
7)SubString方法:字符串的截取
构成重载,当我们给的参数是0,默认会返回原来的字符串,如果index==0,不会产生新对象,否则就会产生新对象
1)public subString(int),返回值是String(提取子串),从指定位置开始到结尾位置提取子串
String str1="abcdef"; String str2=str1.substring(0); System.out.println(str2); //此时str2打印的是abcdef
2)public subString(int,int)返回值是String(提取子串),从指定范围进行截取子串
3)trim()只会进行截取两边的空格,不会进行截取中间的空格,会保留中间的空格
String str1=" abc bc "; String str2=str1.trim();//返回的仍然是new了一个String对象 System.out.println(str2);
像什么验证码会略大小写比较,在操作输入框的时候自动去除掉空格
4)public String toUpperCase()-----字符串转大写(只针对字母),会把小写字母变成大写
5)public String toLowerCase()-----字符串转小写,只会把大写变成小写
6)public int length()-------求字符串长度
7)public boolean IsEmpty()------字符串是否为空
7)String str1="abcdef";
String str2=str1.toUpperCase();
//将小写字母全部变成大写字母,同理str1.toLowerCase是把所有的的大写字母变成小写字母
System.out.println(str2);
8)判断字符串是否为空.isEmpty()方法
String str1="";
System.out.println(str1.isEmpty());----true
1)在这里面我们要注意String str1="";表示这个str1的引用指向一个空字符串,String str2=null,表示str2不会指向任何对象
2)public String intern(),字符串入池操作
concat()方法,出字符串常量池,自动将字符拼接到字符串的末尾
intern()方法,手动入池,表示最后拼接的对象不会进入到常量池里面,会new一个新的对象
String str1="hello".concat("1");
String str2="hello1";
System.out.println(str1==str2);//falsepublic class DemoKail { public static boolean IsAdmin(String array){ return array.toLowerCase()=="admin"; } public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { System.out.println(IsAdmin("Admin")); } } 打印结果为false,toLowerCase()底层new了一个对象
将一个整数转化成字符串:
1)这里面注意一下咱们的Integer.toString()也是可以把一个整数转化成字符串
2)String.valueOf()是将整数转化成字符串,但是Integer.valueOf()是自动拆箱操作,是将一个包装类型转化成基本数据类型类型,也可以将字符串转化成整数
String str1=Integer.toString(10); String str2=String.valueOf(20);
3)我们也是可以将一个自定义类型的数据转化成字符串:
public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); }
class Student{ public String username; public String password; public Student(String username, String password) { this.username = username; this.password = password; } @Override public String toString() { return "Student{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }
Student student=new Student("李佳伟","123456"); System.out.println(String.valueOf(student));
将字符串转化成整数:
int c=Integer.valueOf("8989");
字符串练习题:
输入:abcqwerabc 输出 abcqwer
输入:aaa输出:a
第一种思路:如果说这个字符在StringBuilder中没有出现过,那么直接进行拼接,如果有出现过,那么不会做任何事情
public static void main(String[] args) { Scanner scanner=new Scanner(System.in); while(scanner.hasNextLine()){ String str=scanner.nextLine(); ProcessString(str); } } private static void ProcessString(String str) { StringBuilder stringBuilder=new StringBuilder(); for(int i=0;i<str.length();i++){ char ch=str.charAt(i); if(!stringBuilder.toString().contains(ch+"")){//如果说这个字符没有在字符串中出现过 stringBuilder.append(ch); } } System.out.println(stringBuilder); }
第二种思路:通过LinkedHashSet来进行存储元素
LinkedHashSet<Character> set=new LinkedHashSet<>(); for(int i=0;i<str.length();i++){ char ch=str.charAt(i); set.add(ch); } System.out.println(set.toString()); }
第三种思路:通过标记位的方式来进行去重
我们可以自己new一个boolean数组,因为boolean类型的默认值是false
1)如果说这个字符在数组中没有出现过,那么在数组中默认值就是就是false,咱们就手动进行拼接,并将它的标志位改成true
2)比如说下一次在去访问这个数组的下标的元素的时候,发现标志位已经发生了修改,那么默认不会进行字符串的拼接:
public static void Process(String string){ StringBuilder stringBuilder=new StringBuilder(); boolean[] booleans=new boolean[255]; for(int i=0;i<string.length();i++){ char ch=string.charAt(i); if(booleans[ch]==false) { stringBuilder.append(ch); booleans[ch] = true; } } System.out.println(stringBuilder); }
练习题2:给出两个有序的整数数组A和B,请将数组B合并到数组A中,变成一个有序的数组
输入用例:[4,5,6],[1,2,3]]--->最后的结果是1,2,3,4,5,6
我们保证A数组有足够的空间存放B数组的元素,A中和B中初始的元素数目分别是m和n,但是A的数组空间是m+n
1)我们最终希望的是把B数组的元素放到A数组里面,最终A数组是一个有序的数组,在这里面我们是不允许开辟额外的空间大小的
2)我们跳出第一个循环之后,有可能i走完了,也有可能j走完了,咱们就可以把剩下的数据拷贝到arra1[index]位置,然后index--就可以了;
我们在这里定义三个指针,k只想最后一个大数组的最后一个位置,我们进行比较arr1[i]和arr2[j]的大小,把较大的值放在下标位k的位置
package com.example.demo; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Scanner; public class Solution{ //m表示数组1中有效数据的个数,n表示数组2中有效数据元素的个数 public static int[] merge(int[] arr1, int m, int[] arr2, int n){ int index=m+n-1; int i=m-1; int j=n-1; while(i>=0&&j>=0){ if(arr1[i]>arr2[j]){ arr1[index]=arr1[i]; index--; i--; }else{ arr1[index]=arr2[j]; index--; j--; } } while(j>=0){ arr1[index]=arr2[j]; j--; } while(i>=0){ arr1[index]=arr1[i]; i--; index--; } return arr1; } public static void main(String[] args) { int[] arr1=new int[7]; arr1[0]=11; arr1[1]=12; arr1[2]=90; int[] arr2=new int[4]; arr2[0]=10; arr2[1]=17; arr2[2]=20; arr2[3]=23; int[] array= merge(arr1,3,arr2,4); System.out.println(Arrays.toString(arr1)); } }