【JavaSE】不允许你不会使用String类

  • 🎥 个人主页:深鱼~
  • 🔥收录专栏:JavaSE
  • 🌄欢迎 👍点赞✍评论⭐收藏

目录

前言:

一、常用方法

1.1 字符串构造

1.2 String对象的比较

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

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

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

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

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

1.3 字符串查找

 1.4转化

(1)数值和字符串转化

(2)大小写转换

(3)字符串转数组

(4)格式化

1.5  字符串替换

1.6 字符串拆分

1.7 字符串截取

1.8 其他操作方法

1.9 字符串的不可变性

1.10字符串修改

二、 StringBuilder和StringBuffer

2.1 StringBuilder的介绍

2.2面试题


前言:

在C语言中已经涉及到字符串了,但是在C语言中要表示字符串只能使用字符数组或者字符指针,可以使用标准库提供的字符串系列函数完成大部分操作,但是这种将数据和操作数据方法分离开的方式不符合面相对象的思想,而字符串应用又非常广泛,因此Java语言专门提供了String类。

在开发和校招笔试中,字符串也是常客,比如:

把字符串转换成整数

字符串相加

而且在面试中也频繁被问到,比如:String、StringBuff和StringBulider之间的区别等


一、常用方法

1.1 字符串构造

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

public static void main(String[] args) {//常量字符串String s1 = "Hello World";//直接newString对象String s2 = new String("Hello World");//使用字符数组进行构造char [] array = {'H','e','l','l','o','W','o','r','l','d'};String s3 = new String(array);}

注意:

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

public static void main(String[] args) {// s1和s2引用的是不同对象 s1和s3引用的是同一对象String s1 = new String("hello");String s2 = new String("world");String s3 = s1;
}

 (2) 在Java中“”引起来的也是String类型对象

// 打印"hello"字符串(String对象)的长度
System.out.println("hello".length());

1.2 String对象的比较

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

(1)==比较是否引用同一个对象
注意:对于内置类型,==比较的是变量中的值;对于引用类型==比较的是引用中的地址
public static void main(String[] args) {int a = 10;int b = 20;int c = 10;// 对于基本类型变量,==比较两个变量中存储的值是否相同System.out.println(a == b); // falseSystem.out.println(a == c); // true// 对于引用类型变量,==比较两个引用变量引用的是否为同一个对象String s1 = new String("hello");String s2 = new String("hello");String s3 = new String("world");String s4 = s1;  //s1和s4引用的是同一对象System.out.println(s1 == s2); // falseSystem.out.println(s2 == s3); // falseSystem.out.println(s1 == s4); // true}

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

字典序:字符大小的顺序

String类重写了父类Object中equals方法,Object中equals默认按照==比较,String重写equals方法后,按照如下规则进行比较,比如: s1.equals(s2)

public boolean equals(Object anObject) {// 1. 先检测this 和 anObject 是否为同一个对象比较,如果是返回trueif (this == anObject) {return true;}// 2. 检测anObject是否为String类型的对象,如果是继续比较,否则返回falseif (anObject instanceof String) {// 将anObject向下转型为String类型对象String anotherString = (String) anObject;int n = value.length;// 3. this和anObject两个字符串的长度是否相同,是继续比较,否则返回falseif (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;}
public static void main(String[] args) {String s1 = new String("hello");String s2 = new String("hello");String s3 = new String("Hello");// s1、s2、s3引用的是三个不同对象,因此==比较结果全部为falseSystem.out.println(s1 == s2); // falseSystem.out.println(s1 == s3); // false// equals比较:String对象中的逐个字符// 虽然s1与s2引用的不是同一个对象,但是两个对象中放置的内容相同,因此输出true// s1与s3引用的不是同一个对象,而且两个对象中内容也不同,因此输出falseSystem.out.println(s1.equals(s2)); // trueSystem.out.println(s1.equals(s3)); // false}

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

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

1. 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值

2. 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值

public static void main(String[] args) {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)); // 不同输出字符差值-1System.out.println(s1.compareTo(s3)); // 相同输出 0System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3}

(4) int compareToIgnoreCase(String str) 方法:与compareTo方式相同,但是忽略大小写比较
public static void main(String[] args) {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)); // 不同输出字符差值-1System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3}

1.3 字符串查找

方法功能
char charAt(int index)返回index位置上字符,如果index为负数或者越界,抛出IndexOutOfBoundsException异常
int indexOf(int ch)返回ch第一次出现的位置,没有返回-1
int indexOf(int ch, int fromIndex)从fromIndex位置开始找ch第一次出现的位置,没有返回-1
int indexOf(String str)返回str第一次出现的位置,没有返回-1
int indexOf(String str, int fromIndex)从fromIndex位置开始找str第一次出现的位置,没有返回-1
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 s = "aaabbbcccaaabbbccc";System.out.println(s.charAt(3)); // 'b'System.out.println(s.indexOf('c')); // 6System.out.println(s.indexOf('c', 10)); // 15System.out.println(s.indexOf("bbb")); // 3System.out.println(s.indexOf("bbb", 10)); // 12System.out.println(s.lastIndexOf('c')); // 17System.out.println(s.lastIndexOf('c', 10)); // 8System.out.println(s.lastIndexOf("bbb")); // 12System.out.println(s.lastIndexOf("bbb", 10)); // 3
}

 1.4转化

(1)数值和字符串转化

数字转字符串:String.valueof( )

字符串转数字:Integer.parestInt (字符串) (以转为int类型数据为例)

class Student {public String name;public int age;public Student(String name, int age) {this.name = name;this.age = age;}public String toString() {return "name:" + name + " age:" + age;}
}
public static void main(String[] args) {// 数字转字符串String s1 = String.valueOf(1234);String s2 = String.valueOf(12.34);String s3 = String.valueOf(true);String s4 = String.valueOf(new Student("Hanmeimei", 18));System.out.println(s1);  //1234System.out.println(s2);  //12.34System.out.println(s3);  //trueSystem.out.println(s4);  //name:Hanmeimei age:18需要重写toString方法,否则打印就是Student@1b6d3586System.out.println("=================================");// 字符串转数字// 注意:Integer、Double等是Java中的包装类型,这个后面会讲到int data1 = Integer.parseInt("1234");double data2 = Double.parseDouble("12.34");System.out.println(data1);Sy stem.out.println(data2);
}
(2)大小写转

字符串.toUpperCase()

字符串.toLowerCase()

public static void main(String[] args) {String s1 = "hello";String s2 = "HELLO";// 小写转大写System.out.println(s1.toUpperCase());// 大写转小写System.out.println(s2.toLowerCase());
}
(3)字符串转数组

字符串.toCharArray( )

 public static void main(String[] args) {String s = "hello";// 字符串转数组char[] ch = s.toCharArray();for(char a : ch) {   //遍历数组这样也可以System.out.print(a);}//for (int i = 0; i < ch.length; i++) {//     System.out.print(ch[i]);//}System.out.println();// 数组转字符串String s2 = new String(ch);System.out.println(s2);}
(4)格式化
public static void main(String[] args) {String s = String.format("%d-%d-%d", 2019, 9,14);System.out.println(s);
}
//2019-9-14

1.5  字符串替换

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

方法功能
String replaceAll(String regex, String replacement)替换所有的指定内容
String replaceFirst(String regex, String replacement)替换首个内容

代码示例: 字符串的替换处理

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

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


1.6 字符串拆分

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

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

代码示例: 实现字符串的拆分处理

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

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

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

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

代码示例: 拆分IP地址

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

 注意事项:

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

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

(第一个和第三个\字符转义,转义后是\\,这\\中前面一个也是字符转义,实际上就一个\)

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

代码示例: 多次拆分注意事项:

public static void main(String[] args) {String str = "name=zhangsan&age=18" ;String[] ret  = str.split("&");for (String x: ret) {String[] s = x.split("=");for (String ss: s) {System.out.println(ss);}}}//name
//zhangsan
//age
//18

 这种代码在以后的开发之中会经常出现


1.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));//world
//hello

 注意事项:

1. 索引从0开始

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

(左闭右开)


1.8 其他操作方法

方法功能
String trim()去掉字符串中的左右空格,保留中间空格
String toUpperCase()字符串转大写
String toLowerCase()字符串转小写

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

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

 trim 会去掉字符串开头和结尾的空白字符(空格, 换行, 制表符等).

代码示例: 大小写转换

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

 这两个函数只转换字母


1.9 字符串的不可变性

String是一种不可变对象. 字符串中的内容是不可改变。字符串不可被修改,是因为:

1. String类在设计时就是不可改变的,String类实现描述中已经说明了

以下来自JDK1.8中String类的部分实现

 String类中的字符实际保存在内部维护的value字符数组中,该图还可以看出:

 1. String类被final修饰,表明该类不能被继承

 2. value被修饰被final修饰,表明value自身的值不能改变,即不能引用其它字符数组,但是其引用空间中的内容可以修改。

2. 所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象

比如 replace 方法:

 【纠正】网上有些人说:字符串不可变是因为其内部保存字符的数组被final修饰了,因此不能改变。这种说法是错误的,不是因为String类自身,或者其内部value被final修饰而不能被修改。

final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的。

public static void main(String[] args) {final int array[] = {1,2,3,4,5};array[0] = 100;System.out.println(Arrays.toString(array));// array = new int[]{4,5,6}; // 编译报错:Error:(19, 9) java: 无法为最终变量array分配值
}

 为什么 String 要设计成不可变的?(不可变对象的好处是什么?) (选学)

1. 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑写时拷贝的问题了.

2. 不可变对象是线程安全的.

3. 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中

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


1.10字符串修改

注意:尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率非常低下

public static void main(String[] args) {String s = "hello";s += " world";System.out.println(s); // 输出:hello world
}

 但是这种方式不推荐使用,因为其效率非常低,中间创建了好多临时对象

public static void main(String[] args) {long start = System.currentTimeMillis();String s = "";for(int i = 0; i < 10000; ++i){s += i;} long end = System.currentTimeMillis();System.out.println(end - start);start = System.currentTimeMillis();StringBuffer sbf = new StringBuffer("");for(int i = 0; i < 10000; ++i){sbf.append(i);} end = System.currentTimeMillis();System.out.println(end - start);start = System.currentTimeMillis();StringBuilder sbd = new StringBuilder();for(int i = 0; i < 10000; ++i){sbd.append(i);}end = System.currentTimeMillis();System.out.println(end - start);}

 可以看待在对String类进行修改时,效率是非常慢的,因此:尽量避免对String的直接需要,如果要修改建议尽量使用StringBuffer或者StringBuilder。

b. 借助StringBuffer 和 StringBuilder


二、 StringBuilder和StringBuffer

2.1 StringBuilder的介绍

由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilder和StringBuffer类。这两个类大部分功能是相同的,这里介绍 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的方式返回
 public static void main(String[] args) {StringBuilder sb1 = new StringBuilder("hello");StringBuilder sb2 = sb1;// 追加:即尾插-->字符、字符串、整形数字sb1.append(' '); // hellosb1.append("world"); // hello worldsb1.append(123); // hello world123System.out.println(sb1); // hello world123System.out.println(sb1 == sb2); // trueSystem.out.println(sb1.charAt(0)); // 获取0号位上的字符 hSystem.out.println(sb1.length()); // 获取字符串的有效长度14System.out.println(sb1.capacity()); // 获取底层数组的总大小sb1.setCharAt(0, 'H'); // 设置任意位置的字符 Hello world123sb1.insert(0, "Hello world!!!"); // Hello world!!!Hello world123System.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()方法


2.2面试题

1. String、StringBuffer、StringBuilder的区别

(1)String的内容不可修改StringBuffer与StringBuilder的内容可以修改.

(2)StringBuffer与StringBuilder大部分功能是相似的

(3)StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作


本次内容就到此啦,欢迎评论区或者私信交流,觉得笔者写的还可以,或者自己有些许收获的,麻烦铁汁们动动小手,给俺来个一键三连,万分感谢 !  

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

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

相关文章

如何应用ChatGPT撰写、修改论文及工作报告,提供写作能力及优化工作??

如果我想让gpt从pdf文档中提取相关关键词的内容&#xff0c;可以怎么做呢&#xff1f;&#xff1f;我们评论区讨论 ChatGPT 在论文写作与编程方面也具备强大的能力。无论是进行代码生成、错误调试还是解决编程难题&#xff0c;ChatGPT都能为您提供实用且高质量的建议和指导&am…

轻松管理文件名:文件批量重命名的技巧与操作

在日常工作中&#xff0c;文件管理是一项至关重要的任务。其中&#xff0c;文件名的管理更是关键。文件名是在查找文件时最直观的线索。一个好的文件名简短而准确地反映文件的内容或用途。然而&#xff0c;随着时间的推移&#xff0c;可能会发现文件名变得冗长、混乱甚至无法反…

element-ui表格无法横向拖动问题

是不是用到了fixed // 因为我只有在小屏显示不下的时候才会出现这个问题所以我在这里做了适配(建议把样式放在全局) media screen and (max-width: 1800px) {// 由于使用了fixed导致横向条无法拖动出现bug.Table-page .el-table__fixed {height: auto !important;bottom: 2px …

Leetcode173. 二叉搜索树迭代器

Every day a Leetcode 题目来源&#xff1a;173. 二叉搜索树迭代器 解法1&#xff1a;中序遍历 我们可以直接对二叉搜索树做一次完全的递归遍历&#xff0c;获取中序遍历的全部结果并保存在数组中。随后&#xff0c;我们利用得到的数组本身来实现迭代器。 代码&#xff1a…

【MySQL】子查询

文章目录 子查询IN运算符子查询 VS 连接ALL关键字ANY关键字相关子查询 !EXISTS运算符select子句中的子查询from子句中的子查询 子查询 获取价格大于id为3的货物的商品 用到了内查询&#xff0c;获取id为3的商品的单价&#xff0c;把结构传给外查询 在where子句中编写子查询&am…

车辆管控大数据可视化平台案例源码分析【可视化项目案例-10】

🎉🎊🎉 你的技术旅程将在这里启航! 🚀🚀 本专栏包括但不限于大屏可视化、图表可视化等等。订阅专栏用户在文章底部可下载对应案例源码以供大家深入的学习研究。 🎓 每一个案例都会提供完整代码和详细的讲解,不论你是初学者还是资深开发者,这里都有适合你的内容。…

【双指针】和为 s 的两个数字

和为 s 的两个数字 文章目录 和为 s 的两个数字题目描述算法思路暴力枚举双指针 代码编写Java代码C代码编写 LCR 179. 查找总价格为目标值的两个商品 - 力扣&#xff08;LeetCode&#xff09; 题目描述 购物车内的商品价格按照升序记录于数组 price。请在购物车中找到两个商品…

建行广东省江门市分行走进农村地区开展反假货币宣传

人民对美好生活的向往&#xff0c;涉及方方面面&#xff0c;小至“钱袋子”安全。建行广东省江门市分行落实当地监管部门部署&#xff0c;积极扛起维护国家金融安全的重要政治责任&#xff0c;深入农村地区开展反假货币宣传工作&#xff0c;助力构建农村反假货币工作长效机制。…

Django 入门学习总结4

视图是Django应用程序在Python语言中提供特定的方法并对应于有特定的模板的网页。网页的页面通过视图的方式进行跳转。 在投票系统中&#xff0c;有四个视图&#xff1a; 首页视图&#xff0c;显示最新的问题列表。细节视图&#xff0c;显示问题文本&#xff0c;通过表单可以…

算法刷题-动态规划2(继续)

算法刷题-动态规划2 珠宝的最高价值下降路径最小和使用最小花费爬楼梯整数拆分 珠宝的最高价值 题目 大佬思路 多开一行使得代码更加的简洁 移动到右侧和下侧 dp[ i ][ j ]有两种情况&#xff1a; 第一种是从上面来的礼物最大价值&#xff1a;dp[ i ][ j ] dp[ i - 1 ][ j ]…

【封装UI组件库系列】封装Icon图标组件

封装UI组件库系列第三篇封装Icon图标组件 &#x1f31f;前言 &#x1f31f;封装Icon 1.创建Icon组件 2.引用svg图标库 第一步 第二步 第三步 3.二次封装 4.封装自定义属性 &#x1f31f;总结 &#x1f31f;前言 在前端开发中&#xff0c;大家可能已经用过各种各样的UI组…

cookie的跨站策略 跨站和跨域

借鉴&#xff1a;Cookie Samesite简析 - 知乎 (zhihu.com) 1、跨站指 协议、域名、端口号都必须一致 2、跨站 顶级域名二级域名 相同就行。cookie遵循的是跨站策略