Java字符串
一、Java常用 API
API (Application Programming Interface) :应用程序编程接口,就是别人写好的一些类,给咱们程序员直接拿去调用即可解决问题的
我们前面已经学过的 API 有 Scanner、Random。
但是 Java 中还有很多我们没有学习的类,下图仅一小部分:
但要我们要记住这些类是比较困难的。
这里我们可以使用 Java API 帮助文档来帮助我们使用这些类。
API 帮助文档使用流程:
-
在索引位置搜索自己要查看的类
-
看包
目的:是 java.lang包(核心包),不需要导包代码(import);不是java.lang包,都需要编写导包代码。
-
看这个类的介绍
目的:搞清楚这个类的作用
-
看这个类的构造方法
目的:为了将该类的对象,创建出来
-
看这个类的成员方法(方法摘要)
- 方法名
- 参数
- 返回值
- 介绍
二、String 类
字符串在开发中的应用场景:
1. String 类的特点
- Java 程序中所有双引号字符串, 都是 String 类的对象
- 字符串在创建之后, 其内容不可更改
- 字符串虽然不可改变, 但是可以被共享
1)Java 程序中所有双引号字符串, 都是 String 类的对象
package cn.edu.hgu.string;
public class StringDemo1 {
public static void main(String[] args) {
String s = "abc";
System.out.println(s.toUpperCase());
System.out.println("helloworld".toUpperCase());
}
}
输出结果为:
2)字符串在创建之后, 其内容不可更改
如果想要更改,只能使用新的对象,做替换。
package cn.edu.hgu.string;
public class StringDemo1 {
public static void main(String[] args) {
String s = "abc";
System.out.println(s.hashCode());//输出对象的哈希码
s = "def";
System.out.println(s.hashCode());
}
}
输出结果为:
我们可以看到,两个数的值是不相同的,说明对象进行了替换。
3)字符串虽然不可改变, 但是可以被共享
下面我们来引入一个概念:字符串常量池
字符串常量池:当我们使用双引号创建字符串对象时,会检查常量池中是否存在该数据
我们通过代码来看一下:
package cn.edu.hgu.string;
public class StringDemo1 {
public static void main(String[] args) {
String s1 = "abc";
System.out.println(s1.hashCode());//输出对象的哈希码
String s2 = "abc";
System.out.println(s2.hashCode());
}
}
2. String 类的常见构造方法
构造方法 |
说明 |
public String() |
创建空白字符串,不含任何内容 |
public String(String original) |
根据传入的字符串,创建字符串对象 |
public String(char[] chs) |
根据字符数组,创建字符串对象 |
下面我们来通过代码来使用一下这三个构造方法:
package cn.edu.hgu.string;
public class StringDemo2 {
public static void main(String[] args) {
// public String():创建空白字符串,不含任何内容
String s1 = new String();
System.out.println(s1);
// public String(char[] chs):根据传入的字符数组,创建字符串对象
char[] chs = {'a', 'b', 'c'};
String s2 = new String(chs);
System.out.println(s2);
// public String(String original):根据传入的字符串,来创建字符对象
String s3 = new String("qwer");
System.out.println(s3);
}
}
输出结果为:
注意事项:
3. String 类的常见面试题
面试题1:下面代码结果为:
public class StringTest1 {
public static void main(String[] args) {
String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2);//true
}
}
因为两个变量使用的都是在字符变量池中的同一个变量地址。
面试题2:下面代码结果为:
public class StringTest1 {
public static void main(String[] args) {
String s1 = "abc";
String s2 = new String("abc");
System.out.println(s1 == s2);//false
}
}
s1使用的是字符串中的地址,而s2会在堆内存中新开辟一块内存地址,两个地址是不一样的。
面试题3:下面代码结果为:
public class StringTest1 {
public static void main(String[] args) {
String s1 = "abc";
String s2 = "ab";
String s3 = s2 + "c";
System.out.println(s1 == s3);//false
}
}
s1使用的是在字符串常量池中的地址,字符串进行拼接时会使用 StringBuilder 类,拼接完成后会使用 toString 方法再堆内存中开辟一块地址,两个地址是不相同的。
面试题4:下面代码结果为:
public class StringTest1 {
public static void main(String[] args) {
String s1 = "abc";
String s2 = "a" + "b" + "c";
System.out.println(s1 == s2);//true
}
}
前面讲了字符串在拼接时会调用 StringBuilder 类进行拼接,那为什么结果不对呢?
String s2 = “a” + “b”+“c”;编译器将这个"a" + “b”+“c"作为常量表达式,在编译时进行优化,直接取表达式结果"abc”,这里没有创建新的对象,而是从JVM字符串常量池中获取之前已经存在的"abc"对象。因此a,b具有对同一个string对象的引用,两个引用相等,结果true。
4. String 类用于比较的方法
public boolean equals方法(要比较的字符串) 完全一样结果才是true,否则为false
public boolean equalsIgnoreCase(要比较的字符串) 忽略大小写的比较
下面我们通过案例来学习这两个用于比较的方法:
package cn.edu.hgu.string.method;
public class StringMethodDemo1 {
public static void main(String[] args) {
String s1 = "abc";
String s2 = new String("abc");
System.out.println(s1 == s2);//false
System.out.println(s1.equals(s2));//true
System.out.println("--------------");
String ss1 = "abc";
String ss2 = "ABC";
System.out.println(ss1.equals(ss2));//false
System.out.println(ss1.equalsIgnoreCase(ss2));//true
}
}
输出结果为:
案例:用户登录
需求:已知正确的用户名和密码,请用程序实现模拟用户登录。总共给三次机会,登录之后,给出相应的提示。
分析:
- 定义两个字符串类型变量,模拟已经存在的用户名和密码
- 键盘录入用户输入的用户名,密码
- 比对
代码实现:
package cn.edu.hgu.test;
import java.util.Scanner;
public class StringTest1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 1.定义两个字符串类型变量,模拟已经存在的用户名和密码
String username = "admin";
String password = "123456";
for (int i = 1; i <= 3; i++) {
// 2. 键盘录入用户输入的用户名,密码
System.out.println("请输入用户名:");
String inputUsername = sc.nextLine();
System.out.println("请输入密码:");
String inputPassword = sc.nextLine();
// 3.比对
if (inputUsername.equals(username) && inputPassword.equals(password)) {
System.out.println("登录成功!");
break;
} else {
if (i == 3) {
System.out.println("明儿再来吧~");
} else {
System.out.println("登陆失败,您还剩余" + (3 - i) + "次机会");
}
}
}
}
}
输出结果为:
5. String 字符串的遍历
public char[] toCharArray () 将字符串转换为字符数组
public char chatAt (int index) 根据索引找字符
public int length() : 返回字符串的长度
下面我们来简单了解一下这几个方法的使用:
package cn.edu.hgu.string.method;
public class StringMethodDemo2 {
public static void main(String[] args) {
String s = "itheima";
char[] chars = s.toCharArray();
for (int i = 0; i < chars.length; i++) {
System.out.println(chars[i]);
}
System.out.println("-----------------");
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
System.out.println(c);
}
}
}
输出结果为:
案例:统计字符次数
需求 : 键盘录入一个字符串,统计该字符串中大写字母字符,小写字母字符,数字字符出现的次数(不考虑其他字符)
例如 : aAb3&c2B*4CD1
小写字母 : 3个
大写字母 : 4个
数字字母 : 4个
代码实现:
package cn.edu.hgu.test;
import java.util.Scanner;
public class StringTest2 {
public static void main(String[] args) {
// 1. 键盘录入一个字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入:");
String content = sc.nextLine();
// 2. 定义三份计数器变量,用于统计操作
int smallCount = 0;
int bigCount = 0;
int numCount = 0;
// 3.遍历字符串,获取到每一个字符
char[] chars = content.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
// 4.在遍历的过程中,加入 if 判断,看字符属于哪一种类别
if (c >= 'a' && c <= 'z') {
// 5.对应的计数器变量自增
smallCount++;
} else if (c >= 'A' && c <= 'Z') {
bigCount++;
} else if (c >= '0' && c <= '9') {
numCount++;
}
}
// 6.在遍历结束后,将统计好的计数器变量,打印在控制台
System.out.println("小写字母:" + smallCount + "个");
System.out.println("大写字母:" + bigCount + "个");
System.out.println("数字字符:" + numCount + "个");
}
}
输出结果为:
6. String 字符串的截取方法
public String substring(int beginIndex, int endIndex) 截取
注意点:包头不包尾,包左不包右
只有返回值才是截取的小串
public String substring(int beginIndex) 截取到末尾
下面我们来了解一下这两个方法:
package cn.edu.hgu.string.method;
public class StringMethodDemo3 {
public static void main(String[] args) {
String s = "itheima";
String result1 = s.substring(2);
System.out.println(result1);
System.out.println("----------");
String result2 = s.substring(0, 2);
System.out.println(result2);
}
}
输出结果为:
注意:截取出来的内容,是作为新的字符串返回,别忘记找变量接收
案例:手机号屏蔽
需求:以字符串的形式从键盘接受一个手机号,将中间四位号码屏蔽,最终效果为:156****1234
分析:
- 键盘录入字符串
- 截取前三位
- 截取后四位
- 前三位 + “****” +后四位
代码实现:
package cn.edu.hgu.test;
import java.util.Scanner;
public class StringTest3 {
public static void main(String[] args) {
// 1.键盘录入字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入手机号:");
String tel = sc.nextLine();
// 2. 截取前三位
String start = tel.substring(0, 3);
// 3. 截取后四位
String end = tel.substring(7);
// 4. 前三位 + "****" +后四位
System.out.println(start + "****" + end);
}
}
输出结果为:
7. String 字符串的替换方法
public String replace(旧值,新值) 替换
注意点:返回值才是替换之后的结果
下面我们来学习一下这个方法:
package cn.edu.hgu.string.method;
public class StringMethodDemo4 {
public static void main(String[] args) {
String s = "itheima";
System.out.println("原字符串为:" + s);
String result = s.replace("heima", "baima");
System.out.println("替换后的字符串为:" + result);
}
}
输出结果为:
案例:敏感词替换
需求:键盘录入一个 字符串,如果字符串中包含(TMD),则使用 *** 替换
示例:
辅助你 TMD 是不是有病, 你出无尽干什么 ?
辅助你 *** 是不是有病, 你出无尽干什么 ?
代码实现:
package cn.edu.hgu.test;
import java.util.Scanner;
public class StringTest4 {
/*
需求:键盘录入一个字符串,如果字符串中包含(TMD),则使用 *** 替换
*/
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入:");
String content = sc.nextLine();
content = content.replace("TMD", "***");
System.out.println(content);
}
}
输出结果为:
8. String 字符串的切割方法
public String[] split(String regex) :
根据传入的字符串作为规则进行切割
将切割后的内容存入字符串数组中,并将字符串数组返回
下面我们来学习一下字符串的切割方法:
package cn.edu.hgu.string.method;
public class StringMethodDemo5 {
public static void main(String[] args) {
String s1 = "192,168,1,1";
String[] sArr1 = s1.split(",");
for (int i = 0; i < sArr1.length; i++) {
System.out.println(sArr1[i]);
}
String s2 = "192.168.1.1";
String[] sArr2 = s2.split("\\.");
for (int i = 0; i < sArr2.length; i++) {
System.out.println(sArr2[i]);
}
}
}
输出结果为:
建议:先正常指定切割规则,后来发现没有得到自己要的效果,就可以尝试在规则前面,加入 \
9. String 方法小结
public boolean equals方法 (要比较的字符串) : 比较内容
public boolean equalsIgnoreCase (要比较的字符串) : 比较内容, 忽略大小写
public char[] toCharArray () 将字符串转换为字符数组
public char chatAt (int index) 根据索引找字符
public int length() : 返回字符串的长度
public String substring(int beginIndex) 截取到末尾
public String substring(int beginIndex, int endIndex) 根据开始和结束索引做截取, 包含头不包含尾
public String replace(旧值,新值) 替换
public String[] split(String regex) :切割
三、StringBuilder 类
1. StringBuiler 引入
提高字符串操作效率
我们通过一段代码来看一下是否能提高操作效率:
package cn.edu.hgu.stringbuilder;
public class StringBuilderDemo1 {
public static void main(String[] args) {
long time1 = getTime1();
long time2 = getTime2();
System.out.println("第一次用时:" + time1 + "毫秒");
System.out.println("第二次用时:" + time2 + "毫秒");
}
private static long getTime2() {
long start = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 10000; i++) {
sb.append(i);
}
System.out.println(sb);
long end = System.currentTimeMillis();
long time = end - start;
return time;
}
private static long getTime1() {
// 获取1970年1月1日0分0秒到现在所经历的毫秒值(1秒 = 1000毫秒)
long start = System.currentTimeMillis();
String s = "";
for (int i = 1; i <= 10000; i++) {
s += i;
}
System.out.println(s);
long end = System.currentTimeMillis();
long time = end - start;
return time;
}
}
输出结果为:
可以看到,使用 StringBuilder 类用时明显少于 String 类。
2. StringBuiler
StringBuilder是一种可变的字符序列
package cn.edu.hgu.stringbuilder;
public class StringBuilderDemo2 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
System.out.println(sb);
sb.append("红色");
System.out.println(sb);
sb.append("绿色");
System.out.println(sb);
sb.append("蓝色");
System.out.println(sb);
}
}
输出结果为:
StringBuilder是字符串的缓冲区, 我们可以将其理解为是一种容器,这个容器可以存储任意数据类型,但只要进入到这个容器,全部变成字符串。
package cn.edu.hgu.stringbuilder;
public class StringBuilderDemo2 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append(100);
sb.append(45.6);
sb.append(false);
sb.append('中');
sb.append("黑马程序员");
System.out.println(sb);
}
}
输出结果为:
3. StringBuiler 构造方法
构造方法 |
说明 |
public StringBuilder() |
创建一个空的字符串缓冲区(容器),其初始容量为16个字符 |
public StringBuilder(String str) |
创建一个字符串缓冲区, 并初始化好指定的参数内容 |
4. StringBuiler 常用方法
方法名 |
说明 |
public StringBuilder append (任意类型) |
添加数据,并返回对象本身 |
public StringBuilder reverse() |
反转容器中的内容 |
public int length() |
返回长度 ( 字符出现的个数) |
public String toString() |
通过toString()就可以实现把StringBuilder转换为String |
1)public StringBuilder append (任意类型):
添加数据,并返回对象本身
package cn.edu.hgu.stringbuilder;
public class StringBuilderDemo3 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
StringBuilder sb2 = sb.append("绿色");
StringBuilder sb3 = sb.append("红色");
StringBuilder sb4 = sb.append("蓝色");
System.out.println(sb == sb2);
System.out.println(sb2 == sb3);
System.out.println(sb3 == sb4);
System.out.println(sb4 == sb);
}
}
输出结果为:
因为该方法返回对象本身,那么我们可以使用链式编程来简化代码:
package cn.edu.hgu.stringbuilder;
public class StringBuilderDemo3 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
// 链式编程:调用的方法,返回的结果是对象,就可以继续向下调用方法
sb.append("绿色").append("红色").append("蓝色");
System.out.println(sb);
}
}
2)public StringBuilder reverse()
反转容器中的内容
package cn.edu.hgu.stringbuilder;
public class StringBuilderDemo3 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
// 链式编程:调用的方法,返回的结果是对象,就可以继续向下调用方法
sb.append("绿色").append("红色").append("蓝色");
System.out.println(sb);
sb.reverse().append("你好");
System.out.println(sb);
}
}
输出结果为:
3)public int length()
返回长度
package cn.edu.hgu.stringbuilder;
public class StringBuilderDemo3 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
// 链式编程:调用的方法,返回的结果是对象,就可以继续向下调用方法
sb.append("绿色").append("红色").append("蓝色");
System.out.println(sb);
System.out.println(sb.length());//6
}
}
4)public String toString()
通过toString()就可以实现把StringBuilder转换为String
package cn.edu.hgu.stringbuilder;
public class StringBuilderDemo3 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
// 链式编程:调用的方法,返回的结果是对象,就可以继续向下调用方法
sb.append("绿色").append("红色").append("蓝色");
System.out.println(sb);
// 情况:我数据在StringBuilder当中,我要调用的方法,StringBuilder没有,但String有
// 解决:转换为String类,再调用
String[] sArr = sb.toString().split("色");
for (int i = 0; i < sArr.length; i++) {
System.out.println(sArr[i]);
}
}
}
5. StringBuilder 案例
1)对称字符串
需求:键盘接受一个字符串,程序判断出该字符串是否是对称字符串(回文字符串),并在控制台打印是或不是
-
对称字符串:123321、111
-
非对称字符串:123123
思路:对拿到的字符串进行反转,反转后的内容,根原数据相同,判定为回文字符串
代码实现:
package cn.edu.hgu.test;
import java.util.Scanner;
public class StringBuilderTest1 {
/*
需求:键盘接受一个字符串,程序判断出该字符串是否是对称字符串(回文字符串),并在控制台打印是或不是
*/
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String content = sc.nextLine();
// 将String类型转换为StringBuilder类型,为了调用内部反转的方法
StringBuilder sb = new StringBuilder(content);
String s = sb.reverse().toString();
// 判断反转后的内容,和原数据是否相同
if (content.equals(s)) {
System.out.println("是对称字符串");
} else {
System.out.println("不是对称字符串");
}
}
}
输出结果为:
String类型和StringBuilder类型互相转换:
String ---> StringBUilder
String s = "abc";
StringBuilder sb = new Stringbuilder(sb);
StringBuilder ---> String
String s = sb.toString();
2)拼接字符串
需求:定义一个方法,把 int 数组中的数据按照指定的格式拼接成一个字符串返回。
调用该方法,并在控制台输出结果。
例如:数组为int[] arr = {1,2,3};
执行方法后的输出结果为:[1, 2, 3]
代码实现:
package cn.edu.hgu.test;
public class StringBuilderTest2 {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
StringBuilder result = arrayToString(arr);
System.out.println(result);
}
private static StringBuilder arrayToString(int[] arr) {
// 1.创建StringBuilder,准备进行拼接
StringBuilder sb = new StringBuilder("[");
// 2.遍历数组,获取内部元素
for (int i = 0; i < arr.length - 1; i++) {
// 3.将获取到的元素,拼接到字符串缓冲区
sb.append(arr[i]).append(", ");
}
// 4.特殊处理最后一个元素
sb.append(arr[arr.length - 1]).append("]");
return sb;
}
}
输出结果为:
参考文章:
Java中的常量优化机制
c";
StringBuilder sb = new Stringbuilder(sb);
StringBuilder —> String
String s = sb.toString();
2)拼接字符串
需求:定义一个方法,把 int 数组中的数据按照指定的格式拼接成一个字符串返回。
调用该方法,并在控制台输出结果。
例如:数组为int[] arr = {1,2,3};
执行方法后的输出结果为:[1, 2, 3]
代码实现:
package cn.edu.hgu.test;
public class StringBuilderTest2 {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
StringBuilder result = arrayToString(arr);
System.out.println(result);
}
private static StringBuilder arrayToString(int[] arr) {
// 1.创建StringBuilder,准备进行拼接
StringBuilder sb = new StringBuilder("[");
// 2.遍历数组,获取内部元素
for (int i = 0; i < arr.length - 1; i++) {
// 3.将获取到的元素,拼接到字符串缓冲区
sb.append(arr[i]).append(", ");
}
// 4.特殊处理最后一个元素
sb.append(arr[arr.length - 1]).append("]");
return sb;
}
}
输出结果为:
参考文章:
Java中的常量优化机制