Java(八)——String类

文章目录

  • String类
    • String的构造及内存分布
      • 构造
      • 内存分布
    • 常用方法
      • 判等
      • 比较
      • 查找
      • 转化
      • 替换
      • 拆分
      • 截取
    • 字符串的不可变性
    • StringBuilder和StringBuffer

String类

C语言中没有专门的字符串类型,一般使用字符数组或字符指针表示字符串,而字符串的函数需要包含头文件才能使用,这种数据与方法分离的做法不符合面向对象的思想。

Java中提供了String类来表示字符串


String的构造及内存分布

构造

字符串的构造方式主要有三种:

  1. 常量串构造

    String str1 = "hello";
    
  2. 直接new String对象

    String str2 = new String("hello");
    
  3. 使用字符数组进行构造

    char[] ch = new char[]{'h', 'e', 'l', 'l', 'o'};
    String str3 = new String(ch);
    

内存分布

核心就是 字符串常量池

JDK6及以前,字符串常量池存放在在永久代(内存的永久保存区域)

JDK7之后,字符串常量池存放在

字符串常量构造字符串时,Java在字符串常量池中寻找该字符串的内存地址,找到则将地址赋值给变量,如果没有找到,则在常量池开辟空间并将这块空间赋值该字符串,将这块地址赋值给变量。

new构造字符串时,Java先在堆区开辟一块空间,存放String对象,然后在字符串常量池中寻找字符串的内存地址,找到则将该地址的引用传给堆区的对象,如果没有找到,则在常量池开辟空间并将这块空间赋值该字符串,将地址的引用传给堆区的对象,最后,将堆区对象的地址赋值给变量。

如下代码及内存分布:

    public static void main(String[] args) {String s1 = "hello";String s2 = "hello";String s3 = new String("hello");String s4 = new String("hello");}

在这里插入图片描述

我们在IDEA中观察String的源码:

在这里插入图片描述

我们可以看到,String类中包含很多的成员变量,我们仅关注value数组即可,它存放的就是字符串常量池的某个字符串的地址,其内存分布简单表示如下图:

String str1 = new String("hello");

在这里插入图片描述

字符串非常重要,我们接下来介绍一下Java中字符串的常用方法。


常用方法

判等

字符串的判等区分两种:

  1. ==:判断是否引用同一个对象
  2. boolean equals():判断字符串的内容是否相等

字符串类型是引用类型,==判断两个字符串的地址,而equals()方法判断两个字符串的内容是否相等(无关地址)

我们看下面一段代码,体会==equals()的区别:

public class Test {public static void main(String[] args) {//new了三个不同的对象String str1 = new String("hello");String str2 = new String("HELLO");String str3 = new String("hello");System.out.println(str1 == str2);//不同对象的地址不同System.out.println(str1 == str3);//不同对象的地址不同System.out.println(str1.equals(str2));//两个字符串的内容不同System.out.println(str1.equals(str3));//两个字符串的内容相同System.out.println("=============");str2 = str1;//将引用变量str1的值赋给str2,此时str1和str2指向同一个对象System.out.println(str1 == str2);//指向同一个对象后,地址相同System.out.println(str1.equals(str2));//指向同一个对象,内容自然也相同}
}

打印观察:

在这里插入图片描述


我们再来看一段代码:

    public static void main(String[] args) {String str1 = "hello";String str2 = "HELLO";String str3 = "hello";System.out.println(str1 == str2);//直接指向了字符串常量池的不同字符串,地址当然不同System.out.println(str1 == str3);//直接指向了字符串常量池的同一字符串,地址相同System.out.println(str1.equals(str2));//内容不同System.out.println(str1.equals(str3));//内容相同System.out.println("=============");str2 = str1;System.out.println(str1 == str2);System.out.println(str1.equals(str2));}

打印结果是:
在这里插入图片描述

前后两次区别在于构造字符串的方式不同,第一次是使用new构造,第二次是直接使用常量串构造;

第一次不同对象指向字符串常量池的同一地址,==结果是false;而第二次相同的常量串构造,==结果是true,这刚好验证了我们上面介绍的内存分布情况。


比较

如下两种:

  1. int compareTo()
  2. int compareToIgnoreCase()

【compareTo】

前面介绍的equals()的返回值是boolean类型且只能判断是否相等,而compareTo()返回值是int类型,不同的比较结果返回不同特征的值。

compareTo()比较规则如下:

  1. 先按照字典序大小依次比较,如果出现不等的字符,直接返回两个字符的大小差值
  2. 如果前n个字符都相等(n为要比较的两个字符串的长度较小值),返回两个字符串长度差值
  3. 按照上面的比较规则,如果>就返回一个正数;如果<就返回一个负数;如果==就返回0

例如:

    public static void main(String[] args) {String s1 = new String("hello");String s2 = new String("Hello");String s3 = new String("zero");String s4 = new String("hello");System.out.println(s1.compareTo(s2));//第一个字符'h'与'H'比较,'h' > 'H',所以返回正值System.out.println(s1.compareTo(s3));//第一个字符'h'与'z'比较,'h' < 'z',所以返回负值System.out.println(s1.compareTo(s4));//所有字符依次比较,全部相等,返回0}

在这里插入图片描述


【compareToIgnoreCase】

compareTo()的区别是,compareToIgnoreCase()比较时忽略大小写,如:

    public static void main(String[] args) {String s1 = "HELLO";String s2 = "hello";System.out.println(s1.compareTo(s2));System.out.println(s1.compareToIgnoreCase(s2));}

在这里插入图片描述

注意:

  • compareTo()compareToIgnoreCase()比较时的主体都是调用方法的那个字符串而非传入的参数

查找

char charAt()

int indexOf()及其重载方法

int lastIndexOf()及其重载方法


【charAt】

charAt()方法传入一个int类型的值,这个值即下标值,它将返回指定下标位置的字符(char类型)

    public static void main(String[] args) {String s1 = "hello";System.out.println(s1.charAt(0));System.out.println(s1.charAt(1));System.out.println(s1.charAt(2));System.out.println(s1.charAt(3));System.out.println(s1.charAt(4));}

在这里插入图片描述


【indexOf及其重载方法】

  1. int indexOf(int ch):返回 ch 第一次出现的位置,没有则返回 -1

        public static void main(String[] args) {String s1 = new String("hello");System.out.println(s1.indexOf('h'));System.out.println(s1.indexOf('l'));System.out.println(s1.indexOf('i'));}
    

    在这里插入图片描述

  2. int indexOf(int ch, int fromIndex):从fromIndex(下标值)位置开始找,返 ch 第一次出现的位置,没有找到则返回 -1

        public static void main(String[] args) {String s1 = "abcabcdabcde";System.out.println(s1.indexOf('c', 4));System.out.println(s1.indexOf('f', 0));}
    

    在这里插入图片描述

  3. int indexOf(String str):返回 str 第一次出现的位置,没有找到则返回 -1

        public static void main(String[] args) {String s1 = new String("hello");System.out.println(s1.indexOf("ll"));System.out.println(s1.indexOf("lll"));}
    

    在这里插入图片描述

  4. int indexOf(String str, int fromIndex):从fromIndex(下标值)的位置开始找,返回 str 第一次出现的位置,没有则返回 -1

        public static void main(String[] args) {String s1 = "abcabcdabcde";System.out.println(s1.indexOf("abc", 4));System.out.println(s1.indexOf("abcf", 2));}
    

    在这里插入图片描述


【lastIndexOf】

与前面indexOf()的区别是:查找方向不同lastIndexOf()从后往前找

4种方式:

  • int lastIndexOf(int ch):从后往前找,返回 ch 第一次出现的位置,没有则返回 -1;
  • int lastIndexOf(int ch, int fromIndex):从fromIndex的位置开始从后往前找,返回 ch 第一次出现的位置,没有则返回 -1;
  • int lastIndexOf(String str):从后往前找,返回 str 第一次出现的位置,没有则返回 -1;
  • int lastIndexOf(String str, int fromIndex):从fromIndex的位置开始从后往前找,返回 str 第一次出现的位置,没有则返回 -1;
    public static void main(String[] args) {String s1 = "hello";String s2 = "abcabcdabcde";System.out.println(s1.lastIndexOf('l'));System.out.println(s1.lastIndexOf('l', 2));System.out.println(s2.lastIndexOf("abc"));System.out.println(s2.lastIndexOf("abc", 6));}

在这里插入图片描述


转化

转化部分介绍:

  • 数值和字符串转化
  • 大小写转化
  • 字符串转数组
  • 格式化

【数值和字符串转化】

数值转化为字符串:

String String.valueOf()

字符串转化为数值:

包装类对应类型 包装类.valueOf(String str)

当然不是所有的转化都会成功

注意:需要使用类名调用valueOf()方法,这是因为valueOf()方法被static修饰

在这里插入图片描述

    public static void main(String[] args) {String s1 = String.valueOf(123);int i1 = Integer.valueOf("123");int i2 = Integer.parseInt("123");int i3 = Integer.valueOf("123");double d1 = Double.valueOf("12.2");System.out.println(s1);System.out.println(i1);System.out.println(i2);System.out.println(i3);System.out.println(d1);}

在这里插入图片描述

上图中穿插了一个parseInt()方法,其与valueOf()没有差别,观察valueOf()方法:

发现,valueOf()底层就调用了parseInt()方法


【大小写转化】

转大写:

String toUpperCase()

转小写

String toLowerCase()

public static void main(String[] args) {String s1 = "hello";String s2 = s1.toUpperCase();System.out.println(s2);System.out.println(s2.toLowerCase());
}

在这里插入图片描述


【字符串转数组】

char[] toCharArray()

    public static void main(String[] args) {String s1 = "hello";char[] chars = s1.toCharArray();for (char tmp : chars) {System.out.println(tmp);}}

在这里插入图片描述


【格式化】

String format()

需要了解占位符的知识,Java较少使用,但学过C语言的应该不陌生

    public static void main(String[] args) {String s1 = String.format("%d-%d-%d", 2024, 5, 31);System.out.println(s1);}

在这里插入图片描述


替换

String replace()

String replaceAll(String regex, String replacement):替换所有指定内容

String replaceFirst(String regex, String replacement):替换首个指定内容

    public static void main(String[] args) {String s1 = "hello";String s2 = s1.replace('l', 'o');String s3 = s1.replace("ll", "oo");String s4 = s1.replaceAll("l", "o");String s5 = s1.replaceFirst("ll", "oo");System.out.println(s2);System.out.println(s3);System.out.println(s4);System.out.println(s5);}

在这里插入图片描述


拆分

  1. String[] split(String regex):以regex为分割符拆分字符串,返回一个字符串数组

  2. String[] split(String regex, int limit):将字符串以指定的格式,拆分为limit


String[] split(String regex):以regex为分割符拆分字符】

    public static void main(String[] args) {String s1 = "hello world!";String[] strings1 = s1.split(" ");for (String tmp : strings1) {System.out.print(tmp + " ");}//换行System.out.println();//检验分割后返回的数组System.out.println(Arrays.deepToString(strings1));}

在这里插入图片描述

如果有多个分割符可以使用|,如:

public static void main(String[] args) {String s1 = "I am@OK!";String[] strings = s1.split(" |@");System.out.println(Arrays.deepToString(strings));
}

在这里插入图片描述


String[] split(String regex, int limit):将字符串以指定的格式,拆分为limit组】

    public static void main(String[] args) {String s1 = "i am a bit";String[] strings = s1.split(" ", 2);//仅被分为两组System.out.println(Arrays.deepToString(strings));}

在这里插入图片描述


有些特殊字符作为分割符可能无法正确切分,需要加上转义

  • 字符|*,+.都得加上转义字符,即\\
  • 如果想以\为分割符,就得写成\\\\;单独的\不能出现在字符串中,必须以\\表示\
  • 如果一个字符串中有多个分割符,可以使用|作为连字符,上面演示过了
    public static void main(String[] args) {String s1 = "2024.5.31";String[] strings1 = s1.split("\\.");System.out.println(Arrays.deepToString(strings1));String s2 = "2024+5+31";strings1 = s2.split("\\+");System.out.println(Arrays.deepToString(strings1));String s3 = "2024\\5\\31";strings1 = s3.split("\\\\");System.out.println(Arrays.deepToString(strings1));}

在这里插入图片描述


截取

String substring(int beginIndex):从beginIndex下标位置截取到结尾

String substring(int beginIndex, int endIndex):从beginIndex下标位置截取到endIndex - 1下标位置,也就是说[beginIndex, endIndex)


    public static void main(String[] args) {String s1 = "hello world!";String s2 = s1.substring(6);System.out.println(s2);String s3 = s1.substring(6, 11);System.out.println(s3);}

在这里插入图片描述


【补充】

String trim():去掉字符串中的左右空格,保留中间空格

    public static void main(String[] args) {String s1 = new String("  hello world   ");String s2 = s1.trim();System.out.println(s2);}

在这里插入图片描述


字符串的不可变性

String是一种不可变对象。字符串不可修改,我们从String类源码观察:

在这里插入图片描述

如图:

  • 第一个final表示String类不能被继承;

  • 第二个final表示value不能指向新的对象,但是其内容可以改变,我们可以验证这一点:

    public static void main(String[] args) {final String[] strings = new String[]{"hello", " world", "!"};//修改内容,不报错strings[1] = "bit";//修改strings指向的对象,报错!strings = new String[10];}

在这里插入图片描述
在这里插入图片描述

  • 真正决定String不可被修改的是蓝框里的private修饰符,valueprivate修饰,意味着value只能在当前的String类中使用,而String类没有提供valuegetset方法,所以我们没有办法拿到value值,自然就不能修改字符串了。反过来,只要给value提供getset方法,我们就可以修改字符串了。

基于字符串的不可变性,我们补充一点注意点:

上面我们介绍的所有的方法,都不是在原字符串上进行操作的,都是重新创建了一个新的字符串返回


【字符串的追加(拼接)操作】

使用+即可

    public static void main(String[] args) {String s1 = "hello";String s2 = s1 + " world";System.out.println(s2);}

在这里插入图片描述

此操作容易被误认为修改了字符串,其实并不是。

这段代码实际上如此:

    public static void main(String[] args) {StringBuilder stringBuilder = new StringBuilder();stringBuilder.append("hello");stringBuilder.append(" world");String s2 = stringBuilder.toString();System.out.println(s2);}

并不是在原字符串上修改的,而是使用了StringBuilder类,这是个什么类呢?我们接下来讲!


StringBuilder和StringBuffer

Java中字符串的不可变性使得字符串的操作要不断地new新的对象,使得便捷性与效率并不理想。

为了方便字符串的修改,Java提供了StringBuilderStringBuffer两个类String调用这两个类的构造方法或append方法即可实现转化,这两个类中有非常多的操作字符串的方法(包含String类方法并比String类更丰富),如上面展示过的append()追加方法、reverse()反转方法,调用这些方法时无需创建新对象,直接在它们的类对象上操作即可,若要转换成字符串,只需调用toString()方法并接收即可

我们演示一下:

    public static void main(String[] args) {//创建StringBuilder类对象StringBuilder stringBuilder = new StringBuilder("hello");//直接操作stringBuilder.reverse();//转换为字符串String str = stringBuilder.toString();//打印System.out.println(stringBuilder);System.out.println(str);}

在这里插入图片描述

以后我们想要对字符串执行追加操作时,要尽量使用StringBuilderStringBuffer两个类的追加方法,它们的运行效率更高!

StringBuilderStringBuffer类与String类最大的区别就是String类的内容无法修改,而StringBuilderStringBuffer的内容可以修改。


StringBuilderStringBuffer的区别】

  • StringBuffer采用同步处理,属于线程安全操作,用于保障多线程安全
  • StringBuilder未采用同步处理,属于线程不安全操作,用于单线程

那么,我们以后都使用StringBuffer?

不是的。虽然StringBuffer可以保证多线程安全,但是相比StringBuilder多了一把"锁",“开锁” 和 “上锁” 也是会有损耗的,其效率会较低。对于现在的我们,只需要记住,具体场景具体分析,合理选择。


以上就是对 String的所有介绍了
接下来就是异常了,异常结束后,JavaSE的语法部分就基本结束了,后续会将所有的知识整合在一起,发一篇SE语法全集

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/20869.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【云原生】Kubernetes----配置资源管理Secrets与ConfigMaps

目录 一、Secrets &#xff08;一&#xff09;Secrets概述 &#xff08;二&#xff09;Secrets类型 &#xff08;三&#xff09;Secrets使用方式 &#xff08;四&#xff09;创建Secrets 1.陈述式命令创建 1.1 定义用户与密码文件 1.2 使用陈述式命令创建 2.使用base6…

详解智慧互联网医院系统源码:开发医院小程序教学

本篇文章&#xff0c;笔者将详细介绍智慧互联网医院系统的源码结构&#xff0c;并提供开发医院小程序的详细教学。 一、智慧互联网医院系统概述 智慧互联网医院系统涵盖了预约挂号、在线咨询、电子病历、药品管理等多个模块。 二、系统源码结构解析 智慧互联网医院系统的源码…

OpenShift 4 - OpenShift Service Mesh 3 预览

《OpenShift / RHEL / DevSecOps 汇总目录》 了解 OpenShift Service Mesh 3 的变化 OpenShift Service Mesh 是一套在 OpenShift 上安装部署、跟踪监控 Istio 运行环境的实现。红帽在 2023 年底推出了技术预览版的 OpenShift Service Mesh 3&#xff0c;它和目前的 OpenShif…

IP代理池是什么?

从事跨境行业的朋友们总会有一个疑问&#xff0c;为什么自己所合作的IP代理商的IP在使用的过程中账号会有莫名封禁的问题&#xff0c;会不会是自己在使用的过程中错误的操作违反了平台的规则&#xff0c;其实不然有可能会是IP代理池纯净度不高的问题&#xff0c;有可能自己在使…

UI线程和工作线程

引用&#xff1a;windows程序员面试指南 工作线程 只处理逻辑的线程&#xff0c;例如&#xff1a;启动一个线程&#xff0c;用来做一个复杂的计算&#xff0c;计算完成之后&#xff0c;此线程就自动退出&#xff0c;这种线程称为工作线程 UI线程 Windows应用程序一般由窗口…

Ansible05-Ansible进阶(流程控制、Roles角色、加密优化调优等)

目录 写在前面7 Ansible 进阶7.1 流程控制7.1.1 handlers触发器与notify7.1.1.1 未使用handlers7.1.1.2 使用handlers 7.1.2 when判断7.1.2.1 when的语法7.1.2.2 when判断主机名选择模块输出7.1.2.3 when结合register变量 7.1.3 loop/with_items循环7.1.3.1 with_items案例7.1.…

本地公网IP是什么?

本地公网IP&#xff08;Public IP Address&#xff09;是指分配给计算机或设备的可在互联网上直接访问的唯一标识符。每个连接到互联网的设备都会被分配一个公网IP&#xff0c;用于与其他设备进行通信。本地公网IP在网络通信中起到了非常重要的作用&#xff0c;为用户提供了方便…

单实例11.2.0.3迁移到RAC11.2.0.4_使用RMAN 异机恢复

保命法则&#xff1a;先备份再操作&#xff0c;磁盘空间紧张无法备份就让满足&#xff0c;给自己留退路。 场景说明&#xff1a; 1.本文档的环境为同平台、不同版本&#xff08;操作系统版本可以不同&#xff0c;数据库小版本不同&#xff09;&#xff0c;源机器和目标机器部…

[数据集][目标检测]手枪检测数据集VOC+YOLO格式3000张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;3000 标注数量(xml文件个数)&#xff1a;3000 标注数量(txt文件个数)&#xff1a;3000 标注…

STM32作业实现(七)OLED显示数据

目录 STM32作业设计 STM32作业实现(一)串口通信 STM32作业实现(二)串口控制led STM32作业实现(三)串口控制有源蜂鸣器 STM32作业实现(四)光敏传感器 STM32作业实现(五)温湿度传感器dht11 STM32作业实现(六)闪存保存数据 STM32作业实现(七)OLED显示数据 STM32作业实现(八)触摸按…

hadoop配置nfs,window映射nfs

1.修改hadoop配置如下内容,并同步到其它节点 core-site.xml新增配置项 <!-- 允许hadoop用户代理任何其它用户组 --><property><name>hadoop.proxyuser.hadoop.groups</name><value>*</value></property><!-- 允许代理任意服务器…

如何使用KolorPanotourPro制作全景图像网页

目录 前言 KolorPanotourPro是什么 如何制作全景网页 1.拥有全景图 2.导入图片 3.在多张全景图中跳转 4.查看制作的全景网页 结束语 前言 今天是坚持写博客的第十五天&#xff0c;继续为努力和坚持的大家点赞和鼓掌。 书接上文&#xff0c;我们讲了如何使用如何使用A…

【Vulhub】Fastjson 1.2.24_rce复现

文章目录 一&#xff0c;Fastjson是什么&#xff1f;二&#xff0c;fastjson漏洞原理三&#xff0c;判断是否有fastjson反序列化四&#xff0c;复现Fastjson 1.2.24_rce(vulhub)环境配置1.判断是否存在Fastjson反序列化2.反弹shell3.启动RMI服务器4.构造恶意POST请求 一&#x…

[数据集][目标检测]老鼠检测数据集VOC+YOLO格式4107张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4107 标注数量(xml文件个数)&#xff1a;4107 标注数量(txt文件个数)&#xff1a;4107 标注…

linux tomcat版本漏洞升级

Tomcat Session 反序列化代码执行漏洞(CVE-2020-9484) Tomcat 安全限制绕过漏洞(CVE-2018-8034) Tomcat远程代码执行漏洞(CVE-2017-12615) 以上均可以升级版本处理&#xff0c;小版本升级方法 tomcat安装请查看https://blog.csdn.net/qq_42250832/article/details/139015573 1、…

制作ChatPDF之Elasticsearch8.13.4搭建(一)

Elasticsearch8.x搭建 在Windows系统上本地安装Elasticsearch的详细步骤如下&#xff1a; 1. 下载Elasticsearch 访问 Elasticsearch下载页面。选择适用于Windows的版本8.13.4&#xff0c;并下载ZIP文件。 2. 解压文件 下载完成后&#xff0c;找到ZIP文件&#xff08;例如…

AI预测体彩排3采取888=3策略+和值012路一缩定乾坤测试6月1日预测第8弹

今天继续基于8883的大底进行测试&#xff0c;今天继续测试&#xff0c;好了&#xff0c;直接上结果吧~ 首先&#xff0c;888定位如下&#xff1a; 百位&#xff1a;8,9,7,6,4,3,2,0 十位&#xff1a;4,5,3,2,7,8,0,9 个位&#xff1a;3,4,5,2,…

Centos 7部署NTP

介绍 NTP是Network Time Protocol&#xff08;网络时间协议&#xff09;的简称&#xff0c;它是用来通过互联网或局域网将计算机时钟同步到世界协调时间&#xff08;UTC&#xff09;的协议。 安装 # yum安装 yum install -y ntp# 离线安装 #下载地址&#xff1a;https://mir…

Golang | Leetcode Golang题解之第126题单词接龙II

题目&#xff1a; 题解&#xff1a; //bfsdfs(如果是双向bfs&#xff0c;效果会更好) func findLadders(beginWord string, endWord string, wordList []string) [][]string {//字典表&#xff08;将wordList中的单词放入hash表中&#xff0c;方便查找&#xff09;dict:make(m…

接口测试之XML响应断言

目录 XPath 基本语法XML 响应结果解析XML 响应结果断言 XML 响应数据 如何提取 AddResult 中的值&#xff1f; <soap:Body><AddResponse xmlns"http://tempuri.org/"><AddResult>4</AddResult></AddResponse> </soap:Body> …