- 1.API
- 1.1API概述
- 1.2如何使用API帮助文档
- 2.String类
- 2.1String类概述
- 2.2String类的特点
- 2.3String类的构造方法
- 2.4创建字符串对象两种方式的区别
- 2.5字符串的比较
- 2.5.1==号的作用
- 2.5.2equals方法的作用
- 2.6用户登录案例
- 2.6.1案例需求
- 2.6.2代码实现
- 2.7遍历字符串案例
- 2.7.1案例需求
- 2.7.2代码实现
- 2.8统计字符次数案例
- 2.8.1案例需求
- 2.8.2代码实现
- 2.9字符串拼接案例
- 2.9.1案例需求
- 2.9.2代码实现
- 2.10字符串反转案例
- 2.10.1案例需求
- 2.10.2代码实现
- 关于字符串的四个小扩展:
- 3.StringBuilder
- 3.1、StringBuilder构造方法
- 3.2、StringBuilder成员方法
- 3.3、链式编程
- 3.4、使用StringBuilder场景
- 3.5、String、StringBuffer、StringBuilder三者的对比
- 3.6、StringJoiner
- 4.字符串原理
-
什么是API
API (Application Programming Interface) :应用程序编程接口
-
java中的API
指的就是 JDK 中提供的各种功能的 Java类,这些类将底层的实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用即可,我们可以通过帮助文档来学习这些API如何使用。
- 打开帮助文档
- 找到索引选项卡中的输入框
- 在输入框中输入Random
- 看类在哪个包下
- 看类的描述
- 看构造方法
- 看成员方法
String 类代表字符串,Java 程序中的所有字符串文字(例如“abc”)都被实现为此类的实例。也就是说,Java 程序中所有的双引号字符串,都是 String 类的对象。String 类在 java.lang 包下,所以使用的时候不需要导包!
2.2String类的特点- 字符串不可变,它们的值在创建后不能被更改
- 虽然 String 的值是不可变的,但是它们可以被共享
- 字符串效果上相当于字符数组( char[] ),但是底层原理是字节数组( byte[] )
-
常用的构造方法
方法名 说明 public String() 创建一个空白字符串对象,不含有任何内容 public String(char[] chs) 根据字符数组的内容,来创建字符串对象 public String(byte[] bys) 根据字节数组的内容,来创建字符串对象 String s = “abc”; 直接赋值的方式创建字符串对象,内容就是abc -
示例代码
public class StringDemo01 { public static void main(String[] args) { //public String():创建一个空白字符串对象,不含有任何内容 String s1 = new String(); System.out.println("s1:" + s1); //public String(char[] chs):根据字符数组的内容,来创建字符串对象 char[] chs = {'a', 'b', 'c'}; String s2 = new String(chs); System.out.println("s2:" + s2); //public String(byte[] bys):根据字节数组的内容,来创建字符串对象 byte[] bys = {97, 98, 99}; String s3 = new String(bys); System.out.println("s3:" + s3); //String s = “abc”; 直接赋值的方式创建字符串对象,内容就是abc String s4 = "abc"; System.out.println("s4:" + s4); } }
-
通过构造方法创建
通过 new 创建的字符串对象,每一次 new 都会申请一个内存空间,虽然内容相同,但是地址值不同
-
直接赋值方式创建
以“”方式给出的字符串,只要字符序列相同(顺序和大小写),无论在程序代码中出现几次,JVM 都只会建立一个 String 对象,并在字符串池中维护
- 比较基本数据类型:比较的是具体的值
- 比较引用数据类型:比较的是对象地址值
-
方法介绍
public boolean equals(String s) 比较两个字符串内容是否相同、区分大小写
-
示例代码
public class StringDemo02 { public static void main(String[] args) { //构造方法的方式得到对象 char[] chs = {'a', 'b', 'c'}; String s1 = new String(chs); String s2 = new String(chs); //直接赋值的方式得到对象 String s3 = "abc"; String s4 = "abc"; //比较字符串对象地址是否相同 System.out.println(s1 == s2); System.out.println(s1 == s3); System.out.println(s3 == s4); System.out.println("--------"); //比较字符串内容是否相同 System.out.println(s1.equals(s2)); System.out.println(s1.equals(s3)); System.out.println(s3.equals(s4)); } }
已知用户名和密码,请用程序实现模拟用户登录。总共给三次机会,登录之后,给出相应的提示
2.6.2代码实现
public class StringTest01 {
public static void main(String[] args) {
//已知用户名和密码,定义两个字符串表示即可
String username = "itheima";
String password = "czbk";
//用循环实现多次机会,这里的次数明确,采用for循环实现,并在登录成功的时候,使用break结束循环
for(int i=0; i<3; i++) {
//键盘录入要登录的用户名和密码,用 Scanner 实现
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名:");
String name = sc.nextLine();
System.out.println("请输入密码:");
String pwd = sc.nextLine();
//拿键盘录入的用户名、密码和已知的用户名、密码进行比较,给出相应的提示。字符串的内容比较,用equals() 方法实现
if (name.equals(username) && pwd.equals(password)) {
System.out.println("登录成功");
break;
} else {
if(2-i == 0) {
System.out.println("你的账户被锁定,请与管理员联系");
} else {
//2,1,0
//i,0,1,2
System.out.println("登录失败,你还有" + (2 - i) + "次机会");
}
}
}
}
}
2.7遍历字符串案例
2.7.1案例需求
键盘录入一个字符串,使用程序实现在控制台遍历该字符串
2.7.2代码实现
public class StringTest02 {
public static void main(String[] args) {
//键盘录入一个字符串,用 Scanner 实现
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String line = sc.nextLine();
for(int i=0; i
System.out.println(line.charAt(i));
}
}
}
2.8统计字符次数案例
2.8.1案例需求
键盘录入一个字符串,统计该字符串中大写字母字符,小写字母字符,数字字符出现的次数(不考虑其他字符)
2.8.2代码实现
public class StringTest03 {
public static void main(String[] args) {
//键盘录入一个字符串,用 Scanner 实现
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String line = sc.nextLine();
//要统计三种类型的字符个数,需定义三个统计变量,初始值都为0
int bigCount = 0;
int smallCount = 0;
int numberCount = 0;
//遍历字符串,得到每一个字符
for(int i=0; i
char ch = line.charAt(i);
//判断该字符属于哪种类型,然后对应类型的统计变量+1
if(ch>='A' && ch<='Z') {
bigCount++;
} else if(ch>='a' && ch<='z') {
smallCount++;
} else if(ch>='0' && ch<='9') {
numberCount++;
}
}
//输出三种类型的字符个数
System.out.println("大写字母:" + bigCount + "个");
System.out.println("小写字母:" + smallCount + "个");
System.out.println("数字:" + numberCount + "个");
}
}
2.9字符串拼接案例
2.9.1案例需求
定义一个方法,把 int 数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,
并在控制台输出结果。例如,数组为 int[] arr = {1,2,3}; ,执行方法后的输出结果为:[1, 2, 3]
2.9.2代码实现
public class StringTest04 {
public static void main(String[] args) {
//定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
int[] arr = {1, 2, 3};
//调用方法,用一个变量接收结果
String s = arrayToString(arr);
//输出结果
System.out.println("s:" + s);
}
//定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回
public static String arrayToString(int[] arr) {
//在方法中遍历数组,按照要求进行拼接
String s = "";
s += "[";
for(int i=0; i
if(i==arr.length-1) {
s += arr[i];
} else {
s += arr[i];
s += ", ";
}
}
s += "]";
return s;
}
}
2.10字符串反转案例
2.10.1案例需求
定义一个方法,实现字符串反转。键盘录入一个字符串,调用该方法后,在控制台输出结果
例如,键盘录入 abc,输出结果 cba
2.10.2代码实现
public class StringTest05 {
public static void main(String[] args) {
//键盘录入一个字符串,用 Scanner 实现
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String line = sc.nextLine();
//调用方法,用一个变量接收结果
String s = reverse(line);
//输出结果
System.out.println("s:" + s);
}
//定义一个方法,实现字符串反转
public static String reverse(String s) {
//在方法中把字符串倒着遍历,然后把每一个得到的字符拼接成一个字符串并返回
String ss = "";
for(int i=s.length()-1; i>=0; i--) {
ss += s.charAt(i);
}
return ss;
}
}
关于字符串的四个小扩展:
-
字符串存储的内存原理
String s = “abc”;直接赋值
特点:
此时字符串abc是存在字符串常量池中的。
先检查字符串常量池中有没有字符串abc,如果有,不会创建新的,而是直接复用。如果没有abc,才会创建一个新的。
所以,直接赋值的方式,代码简单,而且节约内存。
-
new出来的字符串
看到new关键字,一定是在堆里面开辟了一个小空间。
String s1 = new String(“abc”);
String s2 = “abc”;
s1记录的是new出来的,在堆里面的地址值。
s2是直接赋值的,所以记录的是字符串常量池中的地址值。
-
==号比较的到底是什么?
如果比较的是基本数据类型:比的是具体的数值是否相等。
如果比较的是引用数据类型:比的是地址值是否相等。
结论:==只能用于比较基本数据类型。不能比较引用数据类型。
-
字符串拼接的时候,没有变量参与
String s = “a” + “b” + “c”;
此时没有变量参与,那么在编译的时候,就已经变成最终的结果了“abc”,这是字符串的常亮优化机制。
-
字符串拼接的时候,有变量参与
String s1 = “a”;
String s2 = s1 + “b”;
在底层,会创建一个StringBuilder对象,再利用append方法,把s1的内容和字符串a都拼接到StringBuilder容器当中,最后再调用toString方法变回一个字符串。在这个过程中,效率比较低,而且内存也有点浪费。
-
StringBuilder提高效率原理图
StringBuilder sb = new StringBuilder();
sb.append(“a”);
sb.append(“b”);
sb.append(“c”);
System.out.println(sb);
我们在代码中,只创建了一个StringBuilder容器对象,把所有的字符串都添加到同一个StringBuilder容器对象当中。而StringBuilder容器对象,里面的内容是可以发生改变的。从头到尾操作的都是同一个,所以效率较高。
StringBuilder可以看作是一个容器,创建之后里面的内容是可变的
作用:提高字符串操作效率
String s1 = "aaa"; String s2 = "bbb"; String s3 = "ccc"; String s4 = "ddd"; String result = s1 + s2 + s3 + s4 传统的String类在拼接过程中会产生多个字符串 StringBuilder中内容是可以改变的的,自始至终就只有一个字符串,效率高3.1、StringBuilder构造方法
public StringBuilder()
构造一个不带任何字符的字符串生成器,其初始容量为 16 个字符。
public StringBuilder(String str)
构造一个初始化为指定字符串内容的字符串构建器。
3.2、StringBuilder成员方法public StringBuilder append(任意类型)
添加数据,并返回数据本身
public StringBuilder reverse()
反转容器中的内容
public int length()
返回长度(字符出现的个数)
public String toString()
通过toString()就可以把StringBuilder转换为String
3.3、链式编程当我们在调用一个方法时,不需要用变量接收它的结果,可以继续调用其他方法
Scanner scan = new Scanner(System.in);
System.out.println("请输入一个字符串");
String str = scan.next();
String result = new StringBuilder().append(str).reverse().toString();
//
if (str.equals(result)){
System.out.println("当前字符串是对称字符串");
}else{
System.out.println("当前字符串不是对称字符串");
}
3.4、使用StringBuilder场景
- 字符串的拼接
- 字符串的反转
String:不可变的字符序列;底层使用char[]存储
StringBuffer:可变的字符序列;线程安全的,效率低;底层使用char[]存储
StringBuilder:可变的字符序列;jdk5.0新增的,线程不安全的,效率高;底层使用char[]存储
JDK8之后
StringJoiner和StringBuilder一样,也可以看成是一个容器,创建之后里面的内容是可变的
作用:提高字符串的操作效率,而且代码编写特别简洁,但是目前市场上很少有人用
构造方法:
public StringJoiner(间隔符号)
创建一个StringJoiner对象,指定拼接时的间隔符号
public StringJoiner(间隔符号,开始符号,结束符号)
创建一个StringJoinger对象,指定拼接时的间隔符号,开始符号,结束符号
成员方法:
public StringJoiner add(添加内容)
添加数据,并返回对象本身
public int length()
返回长度(字符出现的个数)
public String toString()
返回一个字符串(该字符串就是拼接之后的结果)
4.字符串原理-
字符串存储的内存原理
-
直接赋值会复用字符串常量池中的
-
new出来不会复用,而是开辟一个新空间
-
-
==号比较的到底是什么
-
基本数据类型比较数据值
-
引用数据类型比较地址值
-
-
字符串拼接的底层原理
-
拼接的时候没有变量都是字符串触发字符串优化机制,在编译的时候就已经是最优的结果了
-
在拼接的时候有变量存在
JDK8:系统会预估字符串拼接之后的总大小,把要拼接的内容都放在数组中,此时也是产生一个新的字符串。
总结:
- 如果没有变量参与,都是字符串直接相加,编译之后就是拼接之后的结果,会复用串池中的字符串
- 如果有变量参与,每一行拼接的代码,都会在内存中创建新的字符串
-
面试题
String s1 = "abc";//记录串池中的地址值 String s2 = "ab"; String s3 = s2 + "c"; System.out.println(s1 == s3);//false String s1 = "abc";//记录串池中的地址值 String s2 = "a" + "b" + "c";//没有变量触发字符串优化机制,复用串池中的字符串 System.out.println(s1 == s2); //true
-
StringBuilder提高效率原理图
StringBuilder是一个内容可变的容器
所要拼接的内容都会往StringBuilder中放,不会创建很多无用的空间,节约内存
-
StringBuilder源码分析
默认容量:16
长度:实际放了多少
- 默认创建一个长度为16的字节数组
- 添加的内容长度小于16直接存
- 添加的内容大于16会扩容,(原来容量*2 + 2)
- 如果扩容之后还是不够,以实际长度为准



