java基础——String类详解
Posted 爱敲代码的三毛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java基础——String类详解相关的知识,希望对你有一定的参考价值。
一、创建字符串
创建字符串的方式有很多种,当是常见的一般就三种
1. 直接赋值(常用)
String str = "hello world !";
2. new String
String str = new String("hello world !");
3. 字符数组转String
char[] array = {'a', 'b', 'c'};
String str = new String(array);
但以后一般都是用第一种创建方式
注意事项:
- "hello" 这样的字符串字面值常量, 类型也是 String.
- String 也属于引用类型. String str ="Hello"
4.String类中两种对象实例化的区别
- 直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用。
- 构造方法:会开辟两块堆内存空间,不会自动保存在对象池中,可以使用intern()方法手工入池。
二、字符串比较相等
1.直接比较字符串
我们知道两个整形可以直接用 == 比较相等,那如果用 == 比较String类相等会发生什么呢?
代码:
public static void main(String[] args) {
String str1 = "hello";
String str2 = new String("hello");
System.out.println(str1 == str2);
String str3 = "he"+"llo";//编译的时候这个地方相当于 String str3 = "hello";
System.out.println(str1 == str3);
String str4 = "he";
String str5 = "llo";
String str6 = str4+str5;
System.out.println(str1 == str6);
String str7 = "he"+new String("llo");
System.out.println(str1 == str7);
}
运行结果:
我们知道String属于引用类型,所以str存的是地址。那么比较的就是地址。
只要new了就会在堆上开辟内存,所以不相等。直接说可能有点抽象,下面简单通过内存图来判断字符串是否相等。
2.字符串在内存中的存储
接上面的例子我们来看一下字符串在内存中的存储来判断相等
注意:
1.只要new了就会在堆上开辟内存,那么必定不会相等。
2.相同的字符串在字符串常量池里只会存一份。
3.字符串常量池
String类的设计使用了共享设计模式
在JVM底层实际上会自动维护一个对象池(字符串常量池)
- 如果现在采用了直接赋值的模式进行String类的对象实例化操作,那么该实例化对象(字符串内容)将自动保存到这个对象池之中.
- 如果下次继续使用直接赋值的模式声明String类对象,此时对象池之中如若有指定内容,将直接进行引用
- 如若没有,则开辟新的字符串对象而后将其保存在对象池之中以供下次使用
4.字符串比较equals
Java 中要想比较字符串是否相等的话,就需要使用String提供的equals方法
String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1.equals(str2));
// System.out.println(str2.equals(str1)); // 或者这样写也行
// 执行结果
true
equals使用的注意事项:
现在需要比较 str 和 “Hello” 两个字符串是否相等, 我们该如何来写呢?
String str = new String("Hello");
// 方式一
System.out.println(str.equals("Hello"));
// 方式二
System.out.println("Hello".equals(str));
在上面的代码中, 哪种方式更好呢?
更推荐使用 “方式二”. 一旦 str 是 null, 方式一的代码会抛出异常, 而方式二不会
String str = null;
// 方式一
System.out.println(str.equals("Hello")); // 执行结果 抛出 java.lang.NullPointerException 异
常
// 方式二
System.out.println("Hello".equals(str)); // 执行结果 false
注意事项: “Hello” 这样的字面值常量, 本质上也是一个 String 对象, 完全可以使用 equals 等 String 对象的方法
5.理解字符串的不可变
字符串是一种不可变对象. 它的内容不可改变.
String 类的内部实现也是基于 char[] 来实现的, 但是 String 类并没有提供 set 方法之类的来修改内部的字符数组.
代码示例:
String str = "hello" ;
str = str + " world" ;
str += "!!!" ;
System.out.println(str);
// 执行结果
hello world!!!
形如 += 这样的操作, 表面上好像是修改了字符串, 其实不是. 内存变化如下:
+= 之后 str 打印的结果却是变了, 但是不是 String 对象本身发生改变, 而是 str 引用到了其他的对象.
回顾引用:
引用相当于一个指针, 里面存的内容是一个地址. 我们要区分清楚当前修改到底是修改了地址对应内存的内容发生改变了, 还是引用中存的地址改变了.
6.手动入池 intern()
我们知道字符串常量是存在字符串常量池当中的,而new的是在堆上开辟内存。
而String的 intern()方法可以把String对象手动入到字符串常量池中
// 该字符串常量并没有保存在对象池之中
String str1 = "hello" ;
String str2 = new String("hello") ;
System.out.println(str1 == str2);
// 执行结果
false
String str1 = "hello" ;
String str2 = new String("hello").intern() ;
System.out.println(str1 == str2);
// 执行结果
true
如果str2没有
intern()方法的时候,它是指向堆上的new的String对象的,而使用了intern()方法后,就会直接指向字符串常量池的
”hello“,如果调用intern()方法的时候字符串常量池中没有 "hello"这个字符串,则会把它放入池中。
三、字符字节与字符串
1.字符转字符串
代码示例 :
char[] array = {'h','e','l','l','o'};
String str1 = new String(array);
String str2 = new String(array,1,2);
System.out.println(str1);
System.out.println(str2);
//运行结果
//hello
//el
注意:第一个参数是偏移量,偏移量是从0开始的,第二个是参数是往后从偏移量开始的位置走几步。且下标不能越界!
2.字符串转字符
指定获取字符串里的某一个字符:
String str = "hello";
char ch = str.charAt(4);
System.out.println(ch);
//运行结果
//o
字符串转字符数组代码示例:
String str = "hello";
char[] array = str.toCharArray();
for (char s : array) {
System.out.print(s+" ");
}
运行结果
3.字节与字符串
用法和上面的类似
代码示例:
byte[] bytes = {97,98,99,100};
String str = new String(bytes,1,3);
System.out.println(str);
String str2 = "abcd";
byte[] bytes1 = str2.getBytes();
System.out.println(Arrays.toString(bytes1));
运行结果
4.编码方式
运行结果 :
常见的编码方式有 utf-8 和 GBK ,不过编码方式一般只对汉字有影响。
5.小结
那么何时使用 byte[], 何时使用 char[] 呢?
- byte[] 是把 String 按照一个字节一个字节的方式处理, 这种适合在网络传输, 数据存储这样的场景下使用. 更适合 针对二进制数据来操作.
- char[] 是吧 String 按照一个字符一个字符的方式处理, 更适合针对文本数据来操作, 尤其是包含中文的时候
回忆概念: 文本数据 vs 二进制数据
一个简单粗暴的区分方式就是用记事本打开能不能看懂里面的内容.
如果看的懂, 就是文本数据(例如 .java 文件), 如果看不懂, 就是二进制数据(例如 .class 文件).
四、字符串常见操作
1.字符串比较
上面使用过String类提供的equals()方法,该方法本身是可以进行区分大小写的相等判断。除了这个方法之外,String类还提供有如下的比较操作:
代码示例:
String str = "abcd";
System.out.println("abcd".equals(str));![在这里插入图片描述](https://img-blog.csdnimg.cn/20210612164343418.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81Mzk0Njg1Mg==,size_16,color_FFFFFF,t_70#pic_center)
System.out.println("Abcd".equalsIgnoreCase(str));//不区分大小写
//运行结果
//true
//true
**compareTo()**方法前面博客有详细介绍,这里就不多说了。可以看看—>compareTo方法
在String类中compareTo()方法是一个非常重要的方法,该方法返回一个整型,该数据会根据大小关系返回三类内
容:
- 相等:返回0.
- 小于:返回内容小于0.
- 大于:返回内容大于0。
2.字符串查找
从一个完整的字符串之中可以判断指定内容是否存在,对于查找方法有如下定义:
代码示例 :
String str = "abcdefg";
找子串
System.out.println(str.contains("efg"));
从头开始找指定字符串,找到返回下标,找不到返回 -1
System.out.println(str.indexOf("d"));
指定位置开始找指定字符串
System.out.println(str.indexOf("d",2));
从后向前找指定字符串
System.out.println(str.lastIndexOf("fg"));
判断是否以指定字符串开头
System.out.println(str.startsWith("abc"));
从指定位置判断是否以该字符串开头
System.out.println(str.startsWith("de", 3));
用法都是通过 String类点出方法名,注意就收放回值就好了。
3.字符串替换
使用一个指定的新的字符串替换掉已有的字符串数据,可用的方法如下:
代码示例:
String str = "helloworld" ;
System.out.println(str.replaceAll("l", "!"));
System.out.println(str.replaceFirst("l", "!"));
运行结果
注意如果替换的是特殊字符,则需要使用转义字符。
代码示例:
String str1 = "192\\\\168\\\\1\\\\1" ;
System.out.println(str1.replaceAll("\\\\\\\\", "+"));
String str2 = "www.baidu.com";
System.out.println(str2.replaceAll("\\\\.", "%20"));
运行结果
注意事项: 由于字符串是不可变对象, 替换不修改当前字符串, 而是产生一个新的字符串.
4.字符串拆分
可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。
代码示例:
String str1 = "192.168.1.1" ;
String[] array = str1.split("\\\\.");
for (String s : array) {
System.out.println(s);
}
运行结果
注意:下面的的这段代码是不能被拆分的
String str1 = "192\\168\\1\\1" ;
String[] array = str1.split("\\\\\\\\");
for (String s : array) {
System.out.println(s);
}
运行结果:
因为 \\ 后面跟两到三个数字会被转义成一个八进制数字。
注意事项:
- 字符"|","*","+“都得加上转义字符,前面加上”".
- 而如果是"",那么就得写成"\\".
- 如果一个字符串中有多个分隔符,可以用"|"作为连字符.
多次拆分代码示例:
String str = "name=zhangsan&age=18";
String[] result = str.split("&|=") ;
for (String s : result) {
System.out.println(s);
}
运行结果:
5.字符串截取
从一个完整的字符串之中截取出部分内容。
代码示例:
String str = "abcdef";
System.out.println(str.substring(3));
System.out.println(str.substring(2, 4));//左闭右开
运行结果
def
cd
注意事项:
- 索引从0开始
- 注意前闭后开区间的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标
6.其他操作方法
这些都比较简单,用的时候查就好了。
五、StringBuffer 和 StringBuilder
首先来回顾下String类的特点:
任何的字符串常量都是String对象,而且String的常量一旦声明不可改变,如果改变对象内容,改变的是其引用的指向而已。
通常来讲String的操作比较简单,但是由于String的不可更改特性,为了方便字符串的修改,提供StringBuffer和StringBuilder类。
StringBuffer 和 StringBuilder 大部分功能是相同的,只有较小的区别。
1.append()方法
在String中使用"+"来进行字符串连接,但是这个操作在StringBuffer类中需要更改为append()方法:
public synchronized StringBuffer append(各种数据类型 b)
代码示例:
StringBuffer str1 = new StringBuffer("abcd");
StringBuilder str2 = new StringBuilder("abcd");
str1.append(123);
str2.append("hij");
System.out.println(str1);
System.out.println(str2);
运行结果:
StringBuffer 和 StringBuilder 大部分功能是相同的,它们的append()方法的方法可以拼接各种数据类型。
注意:
String和StringBuffer最大的区别在于:String的内容无法修改,而StringBuffer的内容可以修改。频繁修改字符串的情况考虑使用StingBuffer。
因为 String通过+拼接会产生临时对象,而 StringBuffer 和 StringBuilder 只会在当前对象上进行拼接。
2.字符串反转 reverse( )
代码示例:
StringBuffer str1 = new StringBuffer("abcdefg");
StringBuilder str2 = new StringBuilder("654321");
System.out.println(str1.reverse());
System.out.println(str2.reverse());
运行结果:
3.删除指定范围的数据 delete( )
代码示例:
StringBuffer str1 = new StringBuffer("abcdefg");
StringBuilder str2 = new StringBuilder("654321");
System.out.println(str1.delete(2, 5));
System.out.println(str2.delete(4, 6));
运行结果:
4.插入数据 insert( )
代码示例:
StringBuffer str1 = new StringBuffer("abcdefg");
StringBuilder str2 = new StringBuilder("654321");
str1.insert(0,"你好吗").delete(0,1);
System.out.println(str1);
System.out.println(str2.delete(0, 3).insert(0, "你好世界"));
运行结果:
5.StringBuffer 和 StringBuilder的区别
来看一下 StringBuffer 和 StringBuilder 的 append 方法
1.String的拼接会产生临时对象,但是后两者每次都只是返回当前对象的引用
2.String的加号拼接,会被底层优化为一个StringBuilder
3.StringBuilder和String,一般如果不涉及到多线程的情况下才会使用
4.StringBuffer(创建锁、销毁锁、都是耗费资源的)
总结
1.如果以后涉及到字符串的拼接,一定要使用 StringBuffer 和 StringBuilder 的 append()方法
2.注意String类中两种对象实例化的区别
3.相同的字符串在字符串常量池中只会存一份
以上是关于java基础——String类详解的主要内容,如果未能解决你的问题,请参考以下文章