11.1 概念
字符串数据结构中的串,底层是由字符数组来进行封装而成的东西。字符串有一个特别的标志性的符号双引号"",字符串关键词是String,是一种特殊的引用数据类型。
为什么特殊:
1、因为引用数据类型的创建99%都是 类名 对象名=new 类名 (); 字符串的创建 String 变量名="值"字符串的创建与基本数据类型差不多
2、引用数据类型一个的改变会引发另一个的改变,字符串不会
代码语言:javascript复制//nums2的改变会引发nums1的改变
int [] nums1=new int[3];
int []nums2=num1;
nums2[0]=10;
nums2[1]=20;
nums2[2]=30;
Arrays.stream(nums1).forEach(System.out::println);
//因为nums1是完全元素的复制,所以nums2的改变不会引发nums1的变化,因为它们是不同的引用地址
int [] nums1=new int[3];
int []nums2=Arrays.copyOf(num1,num1.length);
nums2[0]=10;
nums2[1]=20;
nums2[2]=30;
Arrays.stream(nums1).forEach(System.out::println);
代码语言:javascript复制//String内部对于这种赋值采用的是完全复制的形式,所以一个的改变不会引发另外一个的变化。
String str1="helloworld";
String str2=str1;
str2="你好世界"
System.out.println(str1);//helloworld
3、字符串是一个非常重要的数据类型,它的使用频率是最高的。
11.2 字符串的创建语法
代码语言:javascript复制//常规创建方式,从字符串常量池中赋值数据
String str="hello world";
//使用new关键字来创建字符串 在读文件的时候会用到new这种情况
String str1=new String("你好世界");
//将其他基本数据类型的数据转换为字符串
String str2=String.valueOf(3);
代码语言:javascript复制public class Main {
public static void main(String[] args) throws IOException {
InputStream resourceAsStream = Main.class.getClassLoader().getResourceAsStream("练习.txt");
byte[] data=new byte[resourceAsStream.available()];
resourceAsStream.read(data);
resourceAsStream.close();
//这是将data byte类型数组中的内容转换为字符串输出,统一编码utf-8
String info=new String(data,"utf-8");
System.out.println(info);
}
}
String在java.lang包下 lang包下的内容在使用的时候不需要导包
11.3 String类中的API
方法名 | 描述 | 案例 |
---|---|---|
char charAt(index) | 返回指定下标的字符 | "hello".charAt(0)-->h |
String concat(String str) | 连接两个字符串 | "hello".concat("world")--> helloworld |
boolean contains(String str) | 查询参数字符串在查找的字符串是否存在,存在返回true,否则false | "helloworld".contains("ow") true |
boolean endsWith(String str) | 检查当前字符串是否以指定的字符串结尾 | "helloworld".endsWith("world"); |
boolean startsWith(String str) | 检查当前字符串是否以指定的字符串开始 | "helloworld".startsWith("he"); |
boolean equals(String str) | 判断两个字符串的值是否相等,区分大小写 | "helloworld".equals("HELLOWORLD")false |
boolean equalsIgnoreCase(String str) | 判断两个字符串的值是否相等,不区分大小写 | "helloworld".equalsIgnoreCase("HELLOWORLD") true |
static String format(String format,Object...args) | 与System.out.printf()一样 | String.format("姓名:%s,年龄:%d,性别:%c","张三",20,'男') 姓名:张三,年龄:20,性别:男 |
byte[] getBytes() | 将指定字符串转换为byte[]数据,一般在操作文件时用 | byte[] data="hello world".getBytes(); |
int indexOf(char ch) | 查找字符在字符串中第一个出现的位置索引,如果没找到返回-1 | "hello world".indexOf('o') 4"hello world".indexOf('z') -1 |
int indexOf(char ch,int startIndex) | 从指定位置索引开始查找字符在字符串中第一个出现的位置索引,如果没找到返回-1 | "hello world".indexOf('o',5) 6 |
int indexOf(String str) | 查找字符串在指定字符串中第一个出现的位置索引,如果没找到返回-1 | "hello world".indexOf("world") 5 |
int indexOf(String str,int startIndex) | 从指定位置查找字符串在指定字符串中第一个出现的位置索引,如果没找到返回-1 | "helloworld------------helloworld".index(world,6):27 |
lastIndexOf(char ch) | 从后向前查找字符在字符串中第一个出现的位置索引,如果没找到返回-1 | "helloworld------------helloworld".lastIndexOf('w') 27 |
lastIndexOf(char ch,int startIndex) | 从后向前指定位置查找字符在字符串中第一个出现的位置索引,如果没找到返回-1 | "helloworld-------helloworld".lastIndexOf('w',26)5 |
lastIndexOf(String str) | 从后向前查找字符串在指定字符串中第一个出现的位置索引,如果没找到返回-1 | "helloworld------------helloworld".lastIndexOf("hello")22 |
lastIndexOf(String str,int startIndex) | 从后向前指定位置查找字符串在指定字符串中第一个出现的位置索引,如果没找到返回-1 | "helloworld------------helloworld".lastIndexOf("hello",20)0 |
int isEmpty() | 判断当前字符串是否为一个没有长度的字符串也就是"" , "" 与null 有本质上的区别,null代表根本就不存在,""字符串已经存在只是里面没有内容 | "".isEmpty() true"helloworld".isEmpty() false |
static String join(连接符,连接字符串列表) | 这是将多个字符串通过指定的连接符组合成一个新的字符串 | String str8=String.join("--",str1,str2,str3,str4); |
int length() | 获取字符串的长度 方法 数组.length是一个属性 | "helloworld".length() |
String replace(char oldChar,char newChar) | 用新的字符替换原字符串中老的字符 | "heiioworid------------heiioworid".replace('l','i'):heiioworid------------heiioworid |
String replace(String oldStr,String newStr) | 用新的字符串替换原字符串中老的字符串 | "heiioworid------------heiioworid".replace("ii","ll"):helloworid------------helloworid |
String substring(int startIndex) | 从指定的下标开始截取到原字符串结尾 | "helloworld".substring(5) world |
String substring(int startindex,int endindex) | 从指定的下标开始截取到结束下标-1为止,包含开始下标,不包含结尾下标 | "helloworld".substring(2,8):llowor"helloworld".substring(2,9) lloworl |
String toLowerCase() | 将字符串中所有的大写字母转换为小写 | "HelloWORLd".toLowerCase():helloworld |
String toUpperCase() | 将字符串中所有的小写字母转换为大写 | "HelloWORLd".toUpperCase():HELLOWORLD |
String trim() | 删除字符串的前后空格,但是中间的空格删除不了 | " hello world ".trim():hello world |
String[] split("拆分符") | 根据指定的符号将字符串拆分为一个数组 | "hello,world,你好,世界!".split(","),结果:,拆分后就没有了,拆分成: hello world 你好 世界!一个数组 |
public class Main {
public static void main(String[] args) throws IOException {
String ch="hello".concat("world");
System.out.println("contains检查是否存在:" ch.contains("你好"));
System.out.println("endsWith检查是否以world结尾:" ch.endsWith("world"));
System.out.println("startsWith检查是否以he开始:" ch.startsWith("he"));
System.out.println("equals:" ch.equals("HELLOWORLD"));
System.out.println("equalsIgnoreCase:" ch.equalsIgnoreCase("HELLOWORLD"));
System.out.println("format:" String.format("姓名:%s,年龄:%d,性别:%c","张三",20,'男'));
byte[] data=ch.getBytes();
System.out.println("===================================================================================");
System.out.println("indexOf查找");
System.out.println("index(char):" ch.indexOf('o'));
System.out.println("index(char,int):" ch.indexOf('o',5));
System.out.println("index(char)没找到:" ch.indexOf('z'));
System.out.println(ch ".index(world):" ch.indexOf("world"));
ch=ch.concat("------------" ch);
System.out.println(ch ".index(world,6):" ch.indexOf("world",6));
System.out.println("===================================================================================");
System.out.println("lastIndexOf从后向前查找");
System.out.println(""" ch "".lastIndexOf('w')" ch.lastIndexOf("w"));
System.out.println(""" ch "".lastIndexOf('w',26)" ch.lastIndexOf("w",26));
System.out.println(""" ch "".lastIndexOf("hello")" ch.lastIndexOf("hello"));
System.out.println(""" ch "".lastIndexOf("hello",20)" ch.lastIndexOf("hello",20));
System.out.println("===================================================================================");
System.out.println("isEmpty是否为空字符串:" ch.isEmpty());
String ch1="";
System.out.println("ch=""isEmpty结果:" ch1.isEmpty());
System.out.println("===================================================================================");
System.out.println("以下都是字符串连接:");
String str1="hello";
String str2="world";
String str3="你好";
String str4="世界";
//使用format连接
String str5=String.format("%s,%s,%s,%s",str1,str2,str3,str4);
//使用 连接符
String str6=str1 "-" str2 "-" str3 "-" str4;
//concat连接
String str7=str1.concat(str2).concat(str3).concat(str4);
//使用join采用可变参数连接
String str8=String.join(">",str1,str2,str3,str4);
String[] strs={str1,str2,str3,str4};
//使用join采用数组在连接
String str9=String.join("---",strs);
//打印连接的结果
System.out.println(str5);
System.out.println(str6);
System.out.println(str7);
System.out.println(str8);
System.out.println(str9);
System.out.println("===================================================================================");
System.out.println("字符串的长度:" ch.length()); //获取字符串的长度
System.out.println("数组的长度:" strs.length); //获取数组的长度
System.out.println("===================================================================================");
System.out.println("以下方法会改变字符串的值");
String ch3=ch.replace('l','i'); //replace不会改变ch原本的值,而会生成一个新的内容这时需要重新对ch赋值
System.out.println(""" ch "".replace('l','i'):" ch3);
String ch2=ch3.replace("ii","ll");
System.out.println(""" ch3 "".replace("ii","ll"):" ch2);
ch="helloworld";
System.out.println(""helloworld".substring(5):" ch.substring(5));
//截取包含开始下标,不包含结尾下标
System.out.println(""helloworld".substring(2,8):" ch.substring(2,8));
System.out.println(""helloworld".substring(2,9):" ch.substring(2,9));
ch="HelloWORLd";
System.out.println(""HelloWORLd".toLowerCase():" ch.toLowerCase());
System.out.println(""HelloWORLd".toUpperCase():" ch.toUpperCase());
ch=" hello world ";
System.out.println("" hello world ".trim():" ch.trim());
System.out.println("===================================================================================");
ch="hello,world,你好,世界!";
String[] split = ch.split(",");
for (String s:split) {
System.out.println(s);
}
}
}
11.4 字符串的比较
== 只能比较字符串的地址
equals做的才是字符串值的等值判断
案例一:值一样,地址一样,那是因为值是从常量池中来的
代码语言:javascript复制public class Main1 {
public static void main(String[] args) {
String str1="hello";
String str2="hello";
System.out.println(str1==str2);
}
}
结果:true
这时str1和str2引用地址一样,为什么地址会一样,字符串常池有关。
在JVM中,为了减少字符串对象的重复创建,维护了一块特殊的内存空间,这块内存空间就被称为字符串常量池。在JDK1.6及之前,字符串常量池存放在方法区中。到JDK1.7之后,就从方法区中移除了,而存放在堆中。
案例二,值一样,地址不一样
代码语言:javascript复制public class Main1 {
public static void main(String[] args) {
String str1=new String("hello"); //初始化 "hello" 常量-->字符串常量池中
String str2=new String("hello"); //"hello"--相同的地址
System.out.println(str1==str2);
}
}
结果:
false
代码语言:javascript复制public class Main1 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入第一个字符串");
String str1=input.next();
System.out.println("请输入第二个字符串:");
String str2=input.next();
System.out.println(str1==str2);
}
}
结果:
false
以上两个案例的数据来源都不是来自于常量池,所以==的结果是false,等值判断要使用equals.equals的源码分析。
代码语言:javascript复制public class Main1 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入第一个字符串");
String str1=input.next();
System.out.println("请输入第二个字符串:");
String str2=input.next();
System.out.println(str1.equals(str2));
}
}
代码语言:javascript复制public boolean equals(Object anObject) {
//this代表的str1 anObject 代表str2
if (this == anObject) {// 如果两个地址一样直接就返回true
return true;
}
//判断参数是不是一个字符串
if (anObject instanceof String) {
//将参数转换为一个字符串对象
String anotherString = (String)anObject;
int n = value.length; //str1的 char数组 放的值
if (n == anotherString.value.length) { //两个对象中的char数组的长度是否一样,不一样肯定就不是相同的字符串
char v1[] = value; //v1表示 str1的值
char v2[] = anotherString.value; //v2表示 str2的值
int i = 0;
while (n-- != 0) { //从最后一个元素开始比较
if (v1[i] != v2[i]) //在这个过程中只要有一个元素不相同就直接返回false
return false;
i ;
}
return true;//如果整个循环结束都没有返回false就一定相同
}
}
return false;
}
11.5 改变字符串值的API
"hello".concat("world");
String.format("姓名:%s,年龄:%d,性别:%c","张三",20,'男')
str1 "-" str2 "-" str3 "-" str4;
ch.replace('l','i');
ch.substring(5)
ch.trim()
以上这些方法会生成一个新的字符串,不会改变原字符串中的值,如果要用新的结果时,需要替换掉原字符串。
课堂练习:
"我爱中国,中国爱我,我是中国人,不骗中国人";请用程序统计中国出现的次数
代码语言:javascript复制public class Main1 {
public static void main(String[] args) {
//请用程序统计中国出现的次数
String str="我爱中国,中国爱我,我是中国人,不骗中国人";
//indexOf() 找到返回下标,找不到返回-1
int count=0;
int index=-1;
int startIndex=0;
do{
index = str.indexOf("中国",startIndex);
if(index==-1){
break;
}
count ;
startIndex=index 2;
}while (true);
System.out.println(count);
}
}
字符串数组排序:
String[] strs={"abc","cbd","nba","abd","bbb","naa","cba"};
代码语言:javascript复制public class Main4 {
public static void main(String[] args) {
String[] strs={"abc","cbd","nba","abd","bbb","naa","cba"};
Arrays.sort(strs);
Arrays.stream(strs).forEach(System.out::println);
}
}
结果:
abc
abd
bbb
cba
cbd
naa
nba
字符串是可以排序的,先排序第一个字符,如果相同再排第二个字符,依次类推。主要排的是每个字符的ASCII码值