对String类的操作 (超细节+演示)

[本节目标]

1.认识String类

2.了解String类的基本用法

3.熟练掌握String类的常见操作

4.认识字符串常量池

5.认识StringBuffer和StringBuilder

1.String类的重要性

在C语言中已经涉及到字符串了,但是在C语言中要表示字符串只能使用字符数组或者字符指针,可以使用标准库提
供的字符串系列函数完成大部分操作,但是这种将数据和操作数据方法分离开的方式不符合面相对象的思想,而字
符串应用又非常广泛,因此Java语言专门提供了String类。
在开发和校招笔试中,字符串也是常客,比如:
字符串转整形数字
字符串相加
而且在面试中也频繁被问到,比如:String、StringBuff和StringBulider之间的区别等。

2.常用方法

2.1. 字符串构造

String类提供的构造方式非常多,常用的就以下三种:

public class Test8 {public static void main(String[] args) {//使用常量串构造String s1 = "hello shousidaima";System.out.println(s1);//直接newString对象String s2 = new String("hello shousidaima");System.out.println(s2);//使用字符数组进行构造char[] arr = {'h','e','l','l','o'};String s3 = new String(arr);System.out.println(s3);}
}

[注意]

1. String是引用类型,内部并不存储字符串本身,在String类的实现源码中,String类实例变量如下:

// s1和s2引用的是不同对象 s1和s3引用的是同一对象
String s1 = new String("hello");
String s2 = new String("world");
String s3 = s1;System.out.println(s1.length()); // 获取字符串长度---输出5
System.out.println(s1.isEmpty()); // 如果字符串长度为0,返回true,否则返回false

2.在java中" "引起来的也是String类型对象.

 System.out.println("hello".length());   //打印长度

2.2 String对象的比较

字符串的比较是常见操作之一,比如:字符串排序。Java中总共提供了4中方式

1. == 比较是否引用同一个对象

对象:对于内置类型, ==比较的是变量中的值:对于引用类型==比较的是引用地址.

int a = 10;
int b = 20;
int c = 10;
// 对于基本类型变量,==比较两个变量中存储的值是否相同
System.out.println(a == b); // false
System.out.println(a == c); // true
// 对于引用类型变量,==比较两个引用变量引用的是否为同一个对象
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = new String("world");
String s4 = s1;
System.out.println(s1 == s2);// false
System.out.println(s2 == s3); // false
System.out.println(s1 == s4); // true

2.boolean equals(Object anObject) 方法:按照字典序比较

字典序:字符大小的顺序

String类重写了父类Object中equals方法,Object中equals默认按照==比较,String重写equals后,按照如下规则比较,比如:s1.equals(s2)   注意!这是java重写的,不是让我们自己重写

@Overridepublic boolean equals(Object anObject) {
// 1. 先检测this 和 anObject 是否为同一个对象比较,如果是返回true
if (this == anObject) {
return true;
}// 2. 检测anObject是否为String类型的对象,如果是继续比较,否则返回false
if (anObject instanceof String) {
// 将anObject向下转型为String类型对象
String anotherString = (String)anObject;
int n = value.length;// 3. this和anObject两个字符串的长度是否相同,是继续比较,否则返回false
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;// 4. 按照字典序,从前往后逐个字符进行比较
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;}}

3.int compartTo(String s)方法:按照字典序进行比较

与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。具体比较方式:

1. 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
2. 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值

String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("abc");
String s4 = new String("abcdef");
System.out.println(s1.compareTo(s2)); // 不同输出字符差值-1
System.out.println(s1.compareTo(s3)); // 相同输出 0
System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3

4. int compareToIgnoreCase(String str) 方法:与compareTo方式相同,但是忽略大小写比较

String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("ABc");
String s4 = new String("abcdef");
System.out.println(s1.compareToIgnoreCase(s2)); // 不同输出字符差值-1
System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0
System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3

2.3 字符串查找

字符串查找也是字符串中非常常见的操作,String类提供的常用查找的方法:
1.char charAt(int index)
返回index位置上字符,如果index为负数或者越界,抛出
IndexOutOfBoundsException异常


2.int indexOf(int ch) 返回ch第一次出现的位置,没有返回-1
3.int indexOf(int ch, int fromIndex) 从fromIndex位置开始找ch第一次出现的位置,没有返回-1


4.int indexOf(String str) 返回str第一次出现的位置,没有返回-1


5.int indexOf(String str, intfromIndex)从fromIndex位置开始找str第一次出现的位置,没有返回-1


6.int lastIndexOf(int ch) 从后往前找,返回ch第一次出现的位置,没有返回-1


7.int lastIndexOf(int ch, int fromIndex)从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返回-1


8. int lastIndexOf(String str) 从后往前找,返回str第一次出现的位置,没有返回-1


9.int lastIndexOf(String str, int fromIndex) 从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返

注意:上述方法都是实例方法。

2.4 转化

1.数值和字符串转化

   // 数字转字符串
String s1 = String.valueOf(1234);
String s2 = String.valueOf(12.34);
String s3 = String.valueOf(true);
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);

// 字符串转数字
// 注意:Integer、Double等是Java中的包装类型,这个后面会讲到
int data1 = Integer.parseInt("1234");
double data2 = Double.parseDouble("12.34");
System.out.println(data1);
System.out.println(data2);

2.大小写转换

String s1 = "hello";
String s2 = "HELLO";

3.字符串转数组

  //字符串转数组
String s1 = "acbd";
char[] arr = s1.toCharArray();for (int i = 0; i < arr.length ;i++) {System.out.println(arr[i]);}//数组转字符串String s2 = new String(arr);System.out.println(s2);

4.格式化

 String s = String.format("%d-%d-%d", 2019, 9,14);
System.out.println(s);

2.5 字符串替换

使用一个指定的新的字符串替换掉已有的字符串数据,可用的方法如下:

String str = "helloworld" ;System.out.println(str.replaceAll("l", "_"));System.out.println(str.replaceFirst("l", "_"));

注意事项: 由于字符串是不可变对象, 替换不修改当前字符串, 而是产生一个新的字符串.

2.6 字符串拆分

可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。
可用方法如下:

方法                                                         功能
String[] split(String regex)                 将字符串全部拆分
String[] split(String regex, int limit)    将字符串以指定的格式,拆分为limit组

代码示例:实现字符串的拆分处理(全部)

 String str = "hello world hello bit" ;String[] result = str.split("l") ; // 按照空格拆分for(String s: result) {
System.out.print(s);}

代码示例:字符串的部分拆分

String str = "hello world hello bit" ;String[] result = str.split("ll",2) ;for(String s: result) {
System.out.println(s);

拆分是特别常用的操作. 一定要重点掌握. 另外有些特殊字符作为分割符可能无法正确切分, 需要加上转义.

代码示例:拆分IP地址

String str = "192.168.1.1" ;String[] result = str.split("\\.") ;for(String s: result) {
System.out.println(s);

注意事项:

1. 字符"|", "*","+"都得加上转义字符,前面加上\\

2.而如果是"\",那么就得写成"\\\\"

3.如果一个字符串中有多个分隔符,可以用"|"作为连字符

代码示例:多次拆分

 String str = "name=zhangsan&age=18" ;String[] result = str.split("&") ;for (int i = 0; i < result.length; i++) {
String[] temp = result[i].split("=") ;
System.out.println(temp[0]+" = "+temp[1]);}}

2.7 字符串截取

从一个完整的字符串之中截取出部分内容。可用方法如下:

方法                                                                    功能
String substring(int beginIndex)                       从指定索引截取到结尾
String substring(int beginIndex, int endIndex) 截取部分内容

 String str = "helloworld" ;System.out.println(str.substring(5));System.out.println(str.substring(0, 5));

注意事项:

1. 索引从0开始
2. 注意前闭后开区间的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标

2.8 其他操作方法

代码示例:观察trim()方法使用

 String str = " hello world " ;System.out.println("["+str+"]");System.out.println("["+str.trim()+"]");

代码示例:大小写转换

  String str = " hello%$$%@#$%world 哈哈哈 " ;System.out.println(str.toUpperCase());System.out.println(str.toLowerCase());

这两个函数只转换字母

2.9  字符串的不可变性

String是一种不可变对象. 字符串中的内容是不可改变。字符串不可被修改,是因为:
1. String类在设计时就是不可改变的,String类实现描述中已经说明了
以下来自JDK1.8中String类的部分实现:


1. String类被final修饰,表明该类不能被继承
2. value被修饰被final修饰,表明value自身的值不能改变,即不能引用其它字符数组,但是其引用空间中
的内容可以修改。
2. 所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象

【纠正】网上有些人说:字符串不可变是因为其内部保存字符的数组被final修饰了,因此不能改变。
这种说法是错误的,不是因为String类自身,或者其内部value被final修饰而不能被修改。
final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的

为什么 String 要设计成不可变的?(不可变对象的好处是什么?) 
1. 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑写时拷贝的问题了.
2. 不可变对象是线程安全的.
3. 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中

那如果想要修改字符串中内容,该如何操作呢?

3.StringBuilder和StringBuffer

3.1 StringBuilder的介绍

由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilder和StringBuffer类。这两个类大部分功能是相同的,这里介绍 StringBuilder常用的一些方法,其它需要用到了大家可参阅 StringBuilder在线文档

方法                                           说明
StringBuff append(String str)        在尾部追加,相当于String的+=,可以追加:boolean、char,char[]、double、float、int、long、Object、String、StringBuff的变量
char charAt(int index)                获取index位置的字符int length() 获取字符串的长度
int capacity()                      获取底层保存字符串空间总的大小
void ensureCapacity(int mininmumCapacity)        扩容
void setCharAt(int index,char ch)                     将index位置的字符设置为ch
int indexOf(String str)              返回str第一次出现的位置
int indexOf(String str, int fromIndex)        从fromIndex位置开始查找str第一次出现的位置
int lastIndexOf(String str)          返回最后一次出现str的位置
int lastIndexOf(String str,int fromIndex)     从fromIndex位置开始找str最后一次出现的位置
StringBuff insert(int offset, String str)          在offset位置插入:八种基类类型 & String类型 & Object类型数据
StringBuffer deleteCharAt(int index)        删除index位置字符
StringBuffer delete(int start, int end)         删除[start, end)区间内的字符
StringBuffer replace(int start, int end, String str)         将[start, end)位置的字符替换为str
String substring(int start)                从start开始一直到末尾的字符以String的方式返回
String substring(int start,int end)      将[start, end)范围内的字符以String的方式返回
StringBuffer reverse()                   反转字符串
String toString()                 将所有字符按照String的方式返回

示例:

import java.util.Arrays;public class Test12 {public static void main(String[] args) {
StringBuilder sb1 = new StringBuilder("hello");
StringBuilder sb2 = sb1;
// 追加:即尾插-->字符、字符串、整形数字sb1.append(' '); // hello
sb1.append("world"); // hello world
sb1.append(123); // hello world123
System.out.println(sb1); // hello world123
System.out.println(sb1 == sb2); // true
System.out.println(sb1.charAt(0)); // 获取0号位上的字符 h
System.out.println(sb1.length()); // 获取字符串的有效长度14
System.out.println(sb1.capacity()); // 获取底层数组的总大小
sb1.setCharAt(0, 'H'); // 设置任意位置的字符 Hello world123
sb1.insert(0, "Hello world!!!"); // Hello world!!!Hello world123
System.out.println(sb1);
System.out.println(sb1.indexOf("Hello")); // 获取Hello第一次出现的位置
System.out.println(sb1.lastIndexOf("hello")); // 获取hello最后一次出现的位置
sb1.deleteCharAt(0); // 删除首字符
sb1.delete(0,5); // 删除[0, 5)范围内的字符
String str = sb1.substring(0, 5); // 截取[0, 5)区间中的字符以String的方式返回
System.out.println(str);
sb1.reverse(); // 字符串逆转
str = sb1.toString(); // 将StringBuffer以String的方式返回
System.out.println(str);
}}

从上述例子可以看出:String和StringBuilder最大的区别在于String的内容无法修改,而StringBuilder的内容可以修改。频繁修改字符串的情况考虑使用StringBuilder。
注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
StringBuilder变为String: 调用toString()方法。

String、StringBuffer、StringBuilder的区别

相同点:底层都是通过char数组实现的
不同点:

String对象一旦创建,其值是不能修改的,如果要修改,会重新开辟内存空间来存储修改之后的对象;而StringBuffer和StringBuilder对象的值是可以被修改的;
StringBuffer几乎所有的方法都使用synchronized实现了同步,线程比较安全,在多线程系统中可以保证数据同步,但是效率比较低;而StringBuilder 没有实现同步,线程不安全,在多线程系统中不能使用 StringBuilder,但是效率比较高。
如果我们在实际开发过程中需要对字符串进行频繁的修改,不要使用String,否则会造成内存空间的浪费;当需要考虑线程安全的场景下使用 StringBuffer,如果不需要考虑线程安全,追求效率的场景下可以使用 StringBuilder。
 

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

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

相关文章

Nacos源码解读04——服务发现

Nacos服务发现的方式 1.客户端获取 1.1:先是故障转移机制判断是否去本地文件中读取信息&#xff0c;读到则返回 1.2:再去本地服务列表读取信息(本地缓存)&#xff0c;没读到则创建一个空的服务&#xff0c;然后立刻去nacos中读取更新 1.3:读到了就返回&#xff0c;同时开启定时…

系列学习前端之第 2 章:一文精通 HTML

全套学习 HTMLCSSJavaScript 代码和笔记请下载网盘的资料&#xff1a; 链接: https://pan.baidu.com/s/1-vY2anBdrsBSwDZfALZ6FQ 提取码: 6666 HTML 全称&#xff1a;HyperText Markup Language&#xff08;超文本标记语言&#xff09; 1、 HTML 标签 1. 标签又称元素&#…

【算法每日一练]-图论(保姆级教程篇12 tarjan篇)#POJ3352道路建设 #POJ2553图的底部 #POJ1236校园网络 #缩点

目录&#xff1a; 今天知识点 加边使得无向图图变成双连通图 找出度为0的强连通分量 加边使得有向图变成强连通图 将有向图转成DAG图进行dp POJ3352&#xff1a;道路建设 思路&#xff1a; POJ2553&#xff1a;图的底部 思路&#xff1a; POJ1236校园网络 思路&#x…

【华为数据之道学习笔记】1-2华为数字化转型与数据治理

传统企业通过制造先进的机器来提升生产效率&#xff0c;但是未来&#xff0c;如何结构性地提升服务和运营效率&#xff0c;如何用更低的成本获取更好的产品&#xff0c;成了时代性的问题。数字化转型归根结底就是要解决企业的两大问题&#xff1a;成本和效率&#xff0c;并围绕…

go写文件后出现大量NUL字符问题记录

目录 背景 看看修改前 修改后 原因 背景 写文件完成后发现&#xff1a; size明显也和正常的不相等。 看看修改前 buf : make([]byte, 64) buffer : bytes.NewBuffer(buf)// ...其它逻辑使得buffer有值// 打开即将要写入的文件&#xff0c;不存在则创建 f, err : os.Open…

solidity案例详解(五)能源电力竞拍合约

使用智能合约对电力公司和用户拍拍进行一个管理与上链&#xff0c;确保安全性&#xff0c;合约完整代码私信 a)现有系统架构和功能&#xff0c;服务提供方是谁&#xff0c;用户是谁&#xff1b; 系统架构&#xff1a; 电力拍卖系统&#xff0c;由能源公司部署。 服务提供方&a…

IntelliJ IDEA创建一个Maven项目

在IDEA中创建Maven项目&#xff0c;前提是已经安装配置好Maven环境 。 本文主要使用的是IntelliJ IDEA 2022.2.1 (Community Edition) 1.创建一个新project:File>Project 2.修改Maven配置&#xff1a;File>Settings>搜索maven 创建好的工程如下&#xff1a; src/main…

记录 | ubuntu监控cpu频率、温度等

ubuntu监控cpu频率、温度等 采用 i7z 进行监控&#xff0c;先安装&#xff1a; sudo apt install i7z -ysudo i7z

STM32单片机项目实例:基于TouchGFX的智能手表设计(3)嵌入式程序任务调度的设计

STM32单片机项目实例&#xff1a;基于TouchGFX的智能手表设计&#xff08;3&#xff09;嵌入式程序任务调度的设计 目录 一、嵌入式程序设计 1.1轮询 1.2 前后台&#xff08;中断轮询&#xff09; 1.3 事件驱动与消息 1.3.1 事件驱动的概念 1.4 定时器触发事件驱动型的任…

如何利用人工智能+物联网技术实现自动化设备生产

随着科技的发展与行业竞争的日益激烈&#xff0c;制造业也逐渐走向智能化发展。制造业的改革是利用物联网技术和自动化设备&#xff0c;实现生产线的智能化和自适应生产&#xff0c;优化生产流程&#xff0c;提高生产效率和质量&#xff0c;为企业创造更大的价值。 方案概述 智…

spring boot定时器实现定时同步数据

文章目录 目录 文章目录 前言 一、依赖和目录结构 二、使用步骤 2.1 两个数据源的不同引用配置 2.2 对应的mapper 2.3 定时任务处理 总结 前言 一、依赖和目录结构 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifa…

自动化定时发送天气提醒邮件

&#x1f388; 博主&#xff1a;一只程序猿子 &#x1f388; 博客主页&#xff1a;一只程序猿子 博客主页 &#x1f388; 个人介绍&#xff1a;爱好(bushi)编程&#xff01; &#x1f388; 创作不易&#xff1a;如喜欢麻烦您点个&#x1f44d;或者点个⭐&#xff01; &#x1f…

redis中缓存雪崩,缓存穿透,缓存击穿等

缓存雪崩 由于原有缓存失效&#xff08;或者数据未加载到缓存中&#xff09;&#xff0c;新缓存未到期间&#xff08;缓存正常从Redis中获取&#xff0c;如下图&#xff09;所有原本应该访问缓存的请求都去查询数据库了&#xff0c;而对数据库CPU和内存造成巨大压力&#xff0c…

STM32单片机项目实例:基于TouchGFX的智能手表设计(2)UI交互逻辑的设计

STM32单片机项目实例&#xff1a;基于TouchGFX的智能手表设计&#xff08;2&#xff09;UI交互逻辑的设计 目录 一、UI交互逻辑的设计 1.1 硬件平台的资源 1.2 界面切换功能 ​​​​​​​1.3 表盘界面 1.4 运动界面 ​​​​​​​1.6 设置界面 ​​​​​​​1.7 应…

vm net 方式 静态ip配置访问主机IP和外网

1、win 11 安装vm&#xff0c;镜像文件 F:\software\VMwork\CentOS-7-x86_64-Everything-1804.iso 2、配置网络 net 方式 3、右击网络--》属性---》更改适配器设置--》vmnet8 属性、这里不做配置会出现主机ping通访问不通的情况&#xff0c;&#xff08;访问不通&#xff0c;…

v4l2接收流程

内核media驱动目录结构 目录media/driver,子目录说明如下&#xff0c;主要列举本文中使用到的目录 目录功能I2C摄像头&#xff0c;解串器&#xff08;max9296/9295等&#xff09;platform控制器的驱动&#xff0c;例如mipi控制等v4l2_coreioctl 入口等media\common\videobuf2…

在python中安装库,会有conda安装,也会有pip安装,conda与pip的区别是什么?

文章目录 一、Conda是什么&#xff1f;二、pip是什么&#xff1f;三、pip与conda的区别&#xff1a;总结 一、Conda是什么&#xff1f; Conda是一个开源的包管理系统&#xff0c;它是Anaconda公司为Python和其他编程语言开发的。它主要用于数据科学和机器学习领域&#xff0c;…

菜鸟学习日记(python)——迭代器与生成器

迭代器 迭代是 Python 最强大的功能之一&#xff0c;是访问集合元素的一种方式。 迭代器是一个可以记住遍历的位置的对象。 迭代器对象从集合的第一个元素开始访问&#xff0c;直到所有的元素被访问完结束。迭代器只能往前不会后退。 迭代器有两个基本的方法&#xff1a;it…

玩转大数据6:实时数据处理与流式计算

引言 在当今的数字化时代&#xff0c;数据正在成为一种新的资源&#xff0c;其价值随着时间的推移而不断增长。因此&#xff0c;实时数据处理和流式计算变得越来越重要。它们在许多领域都有广泛的应用&#xff0c;包括金融、医疗、交通、能源等。本文将探讨实时数据处理和流式…

Nginx的性能优化、安全以及防盗链配置

目录 一、nginx的日志分割 二、nginx性能优化之启用epoll模型 三、nginx性能优化之设置worker进程数并与cpu进行绑核 四、nginx性能优化之调整worker的最大打开文件数和最大处理连接请求数量 五、nginx性能优化之启用gzip压缩&#xff0c;提高传输&#xff0c;减少带宽 六…