当前位置: 首页 > news >正文

深入String、StringBuffer、String 实例化有两种方式、String、StringBuffer常用方法

DAY9.1 Java核心基础

String

String 开发使用的频率高

String 实例化有两种方式

1、直接赋值

String str1 ="Word";

2、通过构造函数创建对象

String str2 =new String("Word");

字符串对象底层的基本数据类型是char

比如Word,是char[] str ={‘W’,‘o’,‘r’,‘d’};

两种实例化的区别

先看一个代码示例:

public static void main(String[] args) {
    String str1 ="Word";
    String str2 ="Word";
    String str3 =new String("Word");
    String str4 =new String("Word");
    System.out.println(str1 == str2);
    System.out.println(str1 == str3);
    System.out.println(str3 == str4);
}

输出:

image-20250310145941027

可以看见虽然这四个对象的值都是一样的,但是str1和str2是相等的,而str1和ster3以及str3和str4是不等的,为什么呢?

这里要提到一个String对象的字符串常量池

当使用String直接赋值创建实例化的时候,会先去字符串常量池寻找是否有这个对象

如果有这个对象则直接返回找到的字符串常量的地址,无需额外在堆内存里面开辟空间

所以在创建str2的时候先去字符串常量池找是否有”Word“的对象,找到了str1对象的值匹配,则返回的str1的地址,所以str1 == str2

具体的 JMM 内存

image-20250310151343445

由上图可以清晰得出这几个String对象的关系

基于上述原因,我们在比较两个字符串是否相等的时候一般调用equels方法,这个方法是String包装类来重写父类Object的equels方法,这样就可以比较值是否相等

public static void main(String[] args) {
    // 直接赋值
    String str1 ="Word";
    String str2 ="Word";
    // 构造器创建
    String str3 =new String("Word");
    String str4 =new String("Word");
    System.out.println(str1.equals(str2));
    System.out.println(str1.equals(str3));
    System.out.println(str3.equals(str4));
}

我们来看看String类里面的equals方法

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

有几个关键节点

  • this == anObject:比较地址是否相等,如果相等肯定值相等,返回true
  • anObject instanceof String :如果不是String类型,则返回false
  • n == anotherString.value.length:比较长度是否相等,如果不相等直接返回false
  • while (n-- != 0):从后往前遍历比较,如果有一位不相等则返回false

String常用方法

方法描述
public String()创建一个值为空的对象
public String(String value)创建一个值为 value 的对象
public String(char[] value)将一个 char 类型数组转为字符串对象
public String(char[] value,int offset,int count)将一个指定范围的 char 类型数组转为字符串对象
public String(byte[] bytes)将一个 byte 类型数组转为字符串对象
public String(byte[] bytes,int offset,int count)将一个指定范围的 byte 类型数组转为字符串对象
public int length()返回字符串的长度
public boolean isEmpty()判断字符串是否为空
public char charAt(int index)返回字符串中指定位置的字符
public byte[] getBytes()将字符串转为 byte 类型数组
public boolean equals(Object obj)判断两个字符串是否相等
public boolean equalsIgnoreCase(String str)判断两个字符串是否相等并且忽略大小写
public int compareTo(String str)对两个字符串进行排序
public boolean startsWith(String str)判断是否以指定的值开头
public boolean endsWith(String str)判断是否以指定的值结尾
public int hashCode()获取字符串的散列值
public int indexOf(String str)从头开始查找指定字符的位置
public int indexOf(String str,int index)从指定的位置开始查找指定字符的位置
public String substring(int index)截取字符串从指定位置开始到结尾
public String substring(int index1,int index2)截取字符串从指定位置开始到指定位置结束
public String concat(String str)追加字符串
public String replaceAll(String str1,String str2)替换字符串
public String[] split(String str)用指定字符串对目标字符串进行分割,返回数组
public String toLowerCase()将字符串转为小写
public String toUpperCase()将字符串转为大写
public char[] toCharArray()将字符串转为 char 数组

StringBuffer

实际开发中使用 String 会存在一个问题,String 对象一旦创建,值是不能修改的

诶,那我这样不就是修改了吗

public static void main(String[] args) {
    String str = "Hello, World!";
    System.out.println(str);
    str = "Word";
    System.out.println(str);
}

NoNoNo,这样不是在String对象修改

str = “Word”;的效果是在堆内存里面创建一个新对象,然后把新对象的地址赋值给str变量,所以知识str变量的地址改变了

String 的值一旦修改,等于重新创建了一个对象进行赋值,而不能在原对象上进行修改

为什么 String 对象一旦修改,不能在原数据上进行修改,而是创建新对象重新赋值?

数组的特点:一旦创建,长度不能修改

因为 String 底层是一个字符数组,所以新的字符串的值无法追加到老字符串的后面,所以只能重新创建一个新的数组来存储新的字符串,所以说 String 的值不能修改(无法在原数据基础上进行修改)

创建的 String 对象,实际上是把字符串的内容存储到一个 char 数组中,String 底层是一个 char 数组

如果开发中需要对某个字符串进行频繁的修改,使用 String 就不合适了,会造成内存空间浪费的问题,如何解决?

使用 StringBuffer 来解决,StringBuffer 和 String 类似,底层也是用一个数组来存储字符串的值,并且默认长度是 16,既一个空的 StringBuffer 对象,数组长度为 16

当我们调用构造器创建一个 StringBuffer 对象时,数组长度就不是 16 了,而是根据当前对象的值来决定数组的长度,值的长度 + 16 作为数组的长度

无论创建的 String Buffer 对象是什么内容,都会预留 16 个长度,就是用来进行修改的

StringBuffer常用方法(和String差不多,实际就是比String更加节约内存)

方法描述
public StringBuffer()无参构造,创建一个空的 StringBuffer 对象
public StringBuffer(String str)有参构造
public synchronized int length()返回 StringBuffer 的长度
public synchronized char charAt(int index)返回字符串中指定位置的字符
public synchronized StringBuffer append(String str)追加字符
public synchronized StringBuffer delete(int start,int end)删除指定区间内的字符
public synchronized StringBuffer deleteCharAt(int index)删除指定位置的字符
public synchronized StringBuffer replace(int start,int end,String str)将指定区间内的值替换为 str
public synchronized String substring(int start)截取字符串从指定位置开始到结尾
public synchronized String substring(int start,int end)截取字符串从指定位置开始到指定位置结束
public synchronized StringBuffer insert(int offset,String str)向指定位置插入 str
public int indexOf(String str)从头开始查找指定字符的位置
public int indexOf(String str,int index)从指定位置开始查找指定字符的位置
public synchronized StringBuffer reverse()进行反转
public synchronized String toString()返回 StringBuffer 对应的 String

但是注意StringBuffer的方法很多有 synchronized 锁,因为StringBuffer具有可操作性

如果一个线程在读的时候另外一个线程在写,那么会导致数据错乱的安全问题

部分方法使用以及反馈:

public static void main(String[] args) {
    StringBuffer stringBuffer = new StringBuffer("Hello");
    // 添加
    stringBuffer.append(" World");
    System.out.println(stringBuffer);
    // 获取长度
    System.out.println(stringBuffer.length());
    // 获取字符
    System.out.println(stringBuffer.charAt(1));
    // 删除
    stringBuffer.delete(0, 5);
    System.out.println(stringBuffer);
    // 插入
    stringBuffer.insert(0, "Hello");
    System.out.println(stringBuffer);
    // 替换
    stringBuffer.replace(0, 5, "World");
    System.out.println(stringBuffer);
    // 截取字符串
    System.out.println(stringBuffer.substring(0, 5));
    // StringBuffer的容量
    System.out.println(stringBuffer.capacity());
    // 获取对应单词的起始位置
    System.out.println(stringBuffer.indexOf("d"));
    // 反转
    System.out.println(stringBuffer.reverse());
}

在这里插入图片描述

相关文章:

  • AHT20 BMP280 STM32C8T6 cubemx
  • 有必要使用 Oracle 向量数据库吗?
  • 蓝桥杯省赛真题C++B组-裁纸刀2022
  • postgresql14编译安装脚本
  • 怎么实现: 大语言模型微调案例
  • AI能否跨越奇点
  • RabbitMQ使用延迟消息
  • 升级到碳纤维齿轮是否值得?
  • CCF-CSP认证 202104-2邻域均值
  • 【js逆向】
  • 牛客周赛:84:C:JAVA
  • 亚信安全发布第七期《勒索家族和勒索事件监控报告》
  • 以太网基础Vlan划分实验
  • C++学习之QT综合项目二经典翻金币小游戏及打包
  • 【LeetCode合并区间C++实现】【c++】【合并区间】
  • javase集合框架List篇
  • ds回答 什么是数据召回
  • 【数据结构】二叉搜索树、平衡搜索树、红黑树
  • 【初探数据结构】带环链表:原理、判断与数学证明
  • 使用 Switch Plus 将 ADTS 文件转为 MP3 格式简单教程
  • 5月2日,全社会跨区域人员流动量完成29275.4万人次
  • 抢抓消费旺季:五一假期,多地党政主官调研外贸优品展销活动
  • 思政课也精彩,“少年修齐讲堂”开讲《我的中国“芯”》
  • 遍体鳞伤就是击不倒,这是国米老男孩最后的倔强
  • 王受文已任中华全国工商业联合会领导班子成员
  • 市场监管总局出手整治涉企乱收费,聚焦政府部门及下属单位等领域