从零开始学Java-字符串

244 阅读15分钟

String字符串简介

  • 概述

    String是Java里的一个类,属于引用类型,遵循引用类型的基本规律和要求。但它也有自己的一些特点,比如可以直接用双引号"......"来表示一个字符串,所以凡是用双引号括起来的一串字符都是String对象,如“Hello”在编译后就会成为一个String对象。另外从名字上我们也可以猜测出,字符串与字符有一定的关系。所以我们可以通过如下方式来表示一个字符串:

    String name = "Hello World";
    
  • 注意点

    字符串内容是不会发生改变的,它的对象在创建后不能被更改。

    凡是有字符串参与拼接的都会产生一个新的字符串。

    String hello1 = "Hello";
    String hello2 = "World";
    System.out.println(hello1 + hello2);  // 产生新的字符串
    

String字符串创建

  • String字符串的定义方式,常用的有如下两种:

    1. 直接赋值:
    String s1 = "Hello World!";
    System.out.println(s1);
    

    2. 通过构造方法创建字符串对象

    构造方法说明
    public String()创建空白字符串,不含任何内容
    public String(Syting original)根据传入的字符串,创建字符串对象
    public String(char[] chs)根据字符数组,创建字符串对象
    public String(byte[] chs)根据字节数组,创建字符串对象
    // 空参构造:创建一个空白的字符串对象
    String s2 = new String();
    System.out.println("s2" + s2 + "!"); // s2!
    
    // 传递一个字符串,根据传递的字符串内容创建一个新的字符串对象。
    String s3 = new String("abc");
    System.out.println(s3);              // abc
    
    // 传递一个字符数组,根据传递的字符数组内容创建一个新的字符串对象。
    char[] chars = {'a','b','c'};
    String s4 = new String(chars);
    System.out.println(s4);              // abc
    
    // 传递一个字节数组,根据传递的字节数组内容创建一个新的字符串对象。
    // 拿着这个数字到ASCII表中去找对应的字母进行拼接
    byte[] bytes = {97,98,99,100};
    String s5 = new String(bytes);
    System.out.println(s5);              // abcd
    

    我们在开发时,其实很少使用第二种方式,因为太过啰嗦,一般都是通过直接赋值的方式进行定义。

String字符串内存原理

  • 1.直接赋值:当使用双引号直接赋值时,系统会检查该字符串在串池是否存在。

    如果不存在就创建新的,如果存在就直接复用。

  • 2.创建赋值

    char[] chs = {'a','b','c'];
    String s1 = new String(chs);
    String s2 = new String(chs);
    

    image.png

    首先main方法进栈,先执行第一行代码。此时就创建出了一个char类型的数组,数组在堆里面开辟了一个新的地址值0x0011并赋值给chs。然后来执行第二行代码,第二行代码等号右边是new出来的,所以在对空间也开辟了一个空间,此时空间的内容是abc,然后把地址值0x0022赋值给s1,第三行的代码其实也是和上面一样,重复执行了一次而已。

String字符串实用方法案例

1. 字符串的比较方法

下面我们来说一下==号比的到底是什么,我们往下看:

  • 基本数据类型:
String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2); // true
  • 引用数据类型:
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2); // false 

s1不是等于s2吗?怎么是false呢?

我们来回想一下,等号右边是什么,是不是new呀,new出来的是不是一个地址值呢?两个地址值肯定不一样呀,所以是false。那这里我们可以得出一个结论啦:

  • 基本数据类型比较的是数据值。

  • 引用数据类型比较的是地址值。

我们再来看一段代码:

String s1 = new String("abc");
String s2 = "abc";
System.out.println(s1 == s2); // false 

这个为什么也是false呢?我们来回想一下,s1是不是new出来的呢?所以是存放在堆空间里面的地址值,而s2是直接赋值的,字符串直接赋值是不是存储在串池里面的地址值呀,两个地方都不一样,所以说也是false啦。

那我如果就是想要比较内容怎么办呢?难道没办法比较吗? image.png

肯定不是啦,在Java中,如果我们想比较两个字符串,其实有两个比较方法:

方法说明使用场景
boolean equals()方法完全一样结果才为true,否则为false密码验证
boolean equalslgnoreCase()方法忽略大小写进行比较验证码验证

我们来实操一下吧:

// 1.创建两个字符串对象进行比较
String s1 = new String("abc");
String s2 = "ABC";

// 2.==号比较
// 基本数据类型,比的是数据值
// 引用数据类型,比的是地址值
System.out.println(s1 == s2); // false

// 3.比较字符串对象中的内容是否相等
boolean result = s1.equals(s2);
System.out.println(result);   // false

// 4.比较字符串对象中的内容是否相等,忽略大小写
boolean result1 = s1.equalsIgnoreCase(s2);
System.out.println(result1);    // true

那这个时候有人就在想了,equalsIgnoreCase() 方法不是忽略大小写吗,那我输入1,一,壹他是不是也能判断相同呀?其实这不行。忽略大小写只能忽略英文的大小写。

我们来看一个验证密码的案例吧:

需求:已知正确用户名和密码,请用程序实现模拟用户登录。 总共给3次机会,登录之后,给出相对应的提示。

第一步:定义正确的用户名和密码

String rightUserName = "zhangsan";
String rightUserPassWord = "123456";

第二步:键盘输入用户名。

Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名:");
String userName = sc.next();

第三步:如果正确就进行判断密码,错误就重新输入

if(userName.equals(rightUserName)){
    System.out.println("您的用户名正确!");
}else{
    System.out.println("您的用户名错误!");
}

第四步:验证密码并提示。

System.out.println("请输入密码:");
String userPasssWord = sc.next();
if(userPasssWord.equals(rightUserPassWord)){
    System.out.println("登录成功!");
}else{
    if(i == 2){
       System.out.println("您的用户名" + rightUserName + "已被锁定");
    }else{
        System.out.println("您的密码错误!还剩下" + (2 - i) + "次机会!");
    }
}

我们来运行看一下吧:

image.png

下面我们来总结一下字符串比较的注意事项有哪些吧:

  • 比较注意事项:

    1.比较两个字符串的内容是否相同,应该使用 equals()equalslgnoreCase方法 方法,而不要使用 == 进行比较。

    2.equalsIgnoreCase()比较方法只能忽略英文的大小写。

2. 字符串的遍历

我们先来说一下获取字符串的4种方法吧!

方法说明
char charAt(int index)获取指定下标位置上对应的字符,并返回char类型
int length()该方法用于返回字符串对象中包含的字符数量,即可以获取字符串的长度
数组名.lenght获取数组的长度
字符串对象.lenght()获取字符串的长度

我们来看一下常用的遍历吧:

// 1.键盘录入一个字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String str = sc.next();
// 2.字符串的遍历
for (int i = 0; i < str.length(); i++) {
    char c = str.charAt(i);
    System.out.print(c + " ");
}

怎么样是不是和数组的遍历是一样的呀!

3. 字符串的截取

方法说明规则
String substring(start,end)截取包头不包尾,包左不包右
String substring(index)截取默认截取到末尾

String substring(start,end):截取范围

String phoneNumber = "13111111111";
// 截取手机号码的前3位
String start = phoneNumber.substring(0, 3);
System.out.println(start);      // 131

String substring(index):截取到末尾

// 截取手机号码后面四位
String end = phoneNumber.substring(7);
System.out.println(end);        // 1111
  • 这里我们需要注意一下:

    1. substring(start,end):包头不包尾,包左不包右。

    2. String substring(index):表示从索引开始位置一直截取到末尾的全部。

4. 字符串的替换

什么是替换呢?我们来看下面这张图片: image.png 他是不是把一些字给替换成星号了呢,你能猜到是什么字吗?那肯定是敏感词呀对不对,那这些是怎么替换的呢我们接着往下看。

方法说明规则
String replace(旧值,新值)替换将旧值替换成新值

我们来实操一下吧:

// 1.定义一个字符串
String str = "你玩的很好,以后不要在玩了,TMD";
// 2.把里面的敏感词替换为星号
String result = str.replace("TMD","***");
System.out.println(result);

image.png

是不是成功把敏感词给替换为星号了呀!

5. 字符串的切割

方法说明规则
String split():切割按照指定的字符串对原字符串进行切割
我们来举个例子:
//字符串切割,按照指定的字符串对原字符串进行切割
String s1 = "zhangsan——lisi——wangwu";
//利用指定的分隔符进行分割,比如利用“——”进行切割
String[] s = s1.split("——");
System.out.println(Arrays.toString(s));

我们运行看一下吧:

image.png

是不是都以逗号隔开了呀!

6. 字符串的大小写转换

方法说明
String toUpperCase():将字符串的字母全部转为大写
String toLowerCase()将字符串的字母全部转为小写
// 字符串大小写转换
String s2 = "abc嘿嘿嘿ABC";
// 将字符串的字母全部变成大写
String s3 = s2.toUpperCase();
System.out.println(s3);
// 将字符串的字母全部变成小写
String s4 = s2.toLowerCase();
System.out.println(s4);

我们运行看一下效果:

image.png

好啦,以上这些方法,就是String字符串中的一些常用方法,当然并不是全部的方法。实际上,String中还有其他的一些方法不是很常用,这里就不再一一列出来啦。

StringBuilder

StringBuilder是什么?为什么要学习StringBuilder呢?

我们来看段代码:

String s = "";
for (int i = 0; i < 1000000; i++) {
    s += "abc";
}
System.out.println(s);

我们来循环拼接这个字符串,我们运行看一下:

image.png 可以看到要循环很多次,也需要非常久的时间才能循环拼接完。

image.png

那有没有什么方法不用等,可以直接拼接完毕的吗?答案是有的,我们接着看使用StringBuilder方法:

StringBuilder s = new StringBuilder(" ");
for (int i = 0; i < 1000000; i++) {
    s.append("abc");
}
System.out.println(s);

我们运行看一下:

image.png 怎么样,是不是秒拼接生成了呢?那下面我们就来说一下什么是StringBuilder吧:

StringBuilder概念

  • StringBuilder可以看成是一个容器,创建之后里面的内容是可以变的

    • 作用:提高字符串的操作效率。
String s1 = "aaa";
String s2 = "bbb";
String s3 = "ccc";
String s4 = "ddd";
String s5 = "eee";

我们使用StringBuilder呢就可以直接装进去了。 image.png 下面我们来说一下StringBuiler构造方法吧!

StringBuilder构造方法

方法名说明
public StringBuilder()创建一个空白可变的字符串对象,不含有任何内容
public StringBuilder(String str)根据字符串内容,来创建可变的字符串对象
  • StringBuilder空参构造:

    StringBuilder s1 = new StringBuilder(); image.png

  • StringBuilder有参构造:

    StringBuilder s1 = new StringBuilder("ABC"); image.png

构造方法我们就讲完了,下面我们来说一下常用方法吧:

StringBuilder成员方法

方法名说明
public StringBuilder append(任意类型)添加数据,并返回对象本身
public StringBuilder reverse()反转容器中的内容
public int lenght()返回长度(字符出现的个数)
public String toString()通过toString()就可以实现把StringBuilder转换为String

是不是感觉有点蒙蒙的,没事,我们把他们全部实操一下吧:

  • StringBuilder append(任意类型)拼接方法
// 1.创建对象
StringBuilder s1 = new StringBuilder("abc");
// 2.添加元素
s1.append(1);
s1.append(8.8);
s1.append(false);
// 打印
System.out.println(s1);

image.png

我们运行可以看到是不是全部都拼接在字符串后面了呀!

  • StringBuilder reverse()反转方法
// 3.反转
s1.reverse();

image.png

他是在容器内直接反转了,和字符串不一样,字符串本身是不能发生变化的,只有返回值才可以替换或者截取的。

  • int lenght()方法
// 4.获取长度
int len = s1.length();
  • String toString()方法
// 1.创建对象
StringBuilder s1 = new StringBuilder();
// 2.添加字符串
s1.append("aaa").append("bbb").append("ccc").append("ddd");
// 3.再把StringBuilder变回字符串
String str = s1.toString();
System.out.println(str);

toString表示把容器内StringBuilder拼接的东西变成字符串返回一个字符串。

  • StringBuilder总结:

    1.StringBuilder是用来帮助我们去操作字符串非常快捷的工具。

    2.StringBuilder是Java已经写好的东西,打印对象不是地址值,而是属性值

    3.使用场景:字符串拼接、字符串反转。

StringJoiner

什么是StringJoiner?为什么要学习StringJoiner呢?

我们还是先来看段代码:

public static String arrTostring(int[] arr){
    StringBuilder s1 = new StringBuilder();
    s1.append("[");
    for (int i = 0; i < arr.length; i++) {
        if (i == arr.length -1){
            s1.append(arr[i]);
        }else{
            s1.append(arr[i]).append(",");
        }
    }
    s1.append("]");
    return s1.toString();
}

image.png

这个案例拼接字符串是不是很麻烦呀,要这里拼一块那里拼一块,那我就在想,有没有一种更方便快捷的方法呢?

image.png

肯定是有的呀,下面我们来体验一下StringJoiner吧:

StringJoiner概念

  • StringJoiner可以看成是一个容器,创建之后里面的内容是可以变的

    • 作用:提高字符串的操作效率,而且代码编写特别简洁。

StringJoiner构造方法

方法名说明
public StringJoiner(间隔符号)创建一个StringJoiner对象,指定拼接时的间隔符号
public StringJoiner(间隔符号,开始符号,结束符号)创建一个StringJoiner对象,指定拼接时的间隔符号、开始符号、结束符号
  • 创建对象的第一种方法: image.png
  • 创建对象的第二种方法: image.png

StringJoiner成员方法

方法名说明
public StringJoiner add(添加的内容)添加数据,并返回对象本身
public int lenght()返回长度(字符出现的个数)
public String toString()返回一个字符串(该字符串就是拼接之后的结果)
  • StringJoiner(间隔符号)方法:

我们先来创建一个对象:

image.png

可以看到他报错了,这里就表示StringJoiner是没有空参构造的,所以需要传一个字符进去。 我们来看一下吧:

// 1.创建一个对象,并指定中间的间隔符号
StringJoiner s1 = new StringJoiner(",");
// 2.添加元素
s1.add("aaa").add("bbb").add("ccc");
// 3.打印
System.out.println(s1);

这个时候运行看一下:

image.png

怎么样,是不是按照我们指定的间隔符号进行间隔了呀!

  • StringJoiner(间隔符号,开始符号,结束符号):
// 1.创建一个对象,并指定中间的间隔符号
StringJoiner s1 = new StringJoiner(",","[","]");
// 2.添加元素
s1.add("aaa").add("bbb").add("ccc");
System.out.println(s1);

我们来运行看一下:

image.png

是不是就自动添加了开始符号和间隔符号以及结束符号了呀!如果我们忘记这三个符号是哪个位置了怎么办呢?没关系,我们可以一个一个试嘛,对吧!

  • int lenght()方法:
// 3.获取长度
int len = s1.length();      // 13

image.png 是不是直接就获取到字符串的长度了呢,和StringBuilder是一样的呢!

  • String toString()方法:
// 4.toString
String str = s1.toString();
System.out.println(str);    // [aaa,bbb,ccc]

image.png

可以看到它返回的也是一个字符串,是不是也和StringBuilder转换成字符串一样的呢!

  • 到这里我们就学完String、StringBuilder、StringJoiner这三个啦,我们来说一下他们的区别吧:
    • String:表示字符串的类,定义了很多操作字符串的方法。
    • StringBuilder:一个可变的操作字符串的容器,可以高效的拼接字符串,还可以反转。
    • StringJoiner:一个可变的操作字符串的容器,可以更高效,方便的拼接字符串。在拼接的时候,可以指定间隔符号、开始符号、结束符号。

字符串原理

字符串存储的内存原理

  • 直接赋值会复用字符串常量池中的数据
  • new出来不会复用,而是开辟一个新的空间

==号比较的是什么

  • 基本数据类型:比较数据值是否相同
  • 引用数据类型:比较的是地址值是否相同

字符串拼接底层原理

我们来看第一种情况:

String s = "a" + "b" + "c";
System.out.println(s);

如果是拼接的时候没有变量,都是字符串,那么就会触发字符串的优化机制。在编译的时候就已经是最终的结果了!

image.png

我们再来看第二种情况:

String s = "a";
String s1 = s + "b";
String s2 = s1 + "c";
System.out.println(s2);

如果是拼接的时候有变量参与,那么底层会使用StringBuilder,在内存中会创建多个对象,浪费空间,时间也非常慢。 image.png

结论:如果很多字符串变量拼接,不要直接+。因为在底层会创建很多个对象,浪费时间,浪费性能。

  • 我们来小结一下吧:

    • 如果没有变量参与,都是字符串直接相加,编译之后就是拼接的结果,会复用串池的字符串。
    • 如果有变量参与,每一行拼接的代码,都会在内存中创建新的字符串,浪费内存。

StringBuilder提高效率原理图

我们来看段代码:

StringBuilder s1 = new StringBuilder();
s1.append("a");
s1.append("b");
s1.append("c");
System.out.println(s1);

我们还记得StringBuilder是什么吗?是不是一个内容可变的容器呀!

image.png

我的答案是:没有达到2147483648都不会爆。

image.png

难道我无限添加也不会爆吗?不是的,我们来看一下源码: image.png 这是什么意思呢? 表示你的长度如果大于int类型的最大容量21亿多的话就会爆了。

  • 我们来小结一下吧:

    • 所有要拼接的内容都会往StringBuilder中放,不会创建很多无用的空间,节约内存。

StringBuilder源码分析

  • 默认创建一个长度为16字节的数组。
  • 添加的内容长度小于16,直接存。
  • 添加的内容大于16就会扩容(原来的容量*2+2)。
  • 如果扩容之后还不够,就以实际长度为准。

好啦,以上就是String字符串的一些常用方法和一些案例。有什么不懂的可以在评论区评论哟!我们下期再见!

==最后非常感谢您的阅读,也希望能得到您的反馈  ==