java基础--字符/字符串2(包含常见相关面试题)

8 篇文章 0 订阅

  上一节主要描述的是String和char的基础简绍以及相关知识。这一节主要介绍String剩下的特点以及StringBuilder和StringBuffer的相关知识与面试题。

Sring类

上一节介绍了两种创建String类的方法,即如下:

//方法一
	String str1 = "Hello";
//方法二
	String str2 = new String ("Hello");

还有其他构造方式,有需要可以查看官方文档Java™ Platform, Standard Edition 8
API Specification

字符串常量池

直接赋值

我们先看一段代码

	String str1 = "hello" ;
	String str2 = "hello" ;
	String str3 = "hello" ;
	System.out.println(str1 == str2); // true
	System.out.println(str1 == str3); // true
	System.out.println(str2 == str3); // true

这段代码的相关内存空间图:
在这里插入图片描述
为什么没有开辟新的堆内存空间呢?String类的设计是用来共享设计模式
在jvm底层实际上会自动维护一个对象池(字符串常量池)

  • 如果现在采用了直接赋值的模式进行String类的对象实例化操作,那么该实例化对象(字符串内容)将自动保存到这个对象池之中.
  • 如果下次继续使用直接赋值的模式声明String类对象,此时对象池之中如若有指定内容,将直接进行引用
  • 如若没有,则开辟新的字符串对象而后将其保存在对象池之中以供下次使用。
构造方法

采用构造方法时,即String str1 = new String(“Hello”);这样的方式创建相当于在堆上另外开辟空间来存储“Hello”的内容。
在这里插入图片描述
这样的做法有两个缺点:

  1. 如果使用String构造方法就会开辟两块堆内存空间,并且其中一块堆内存将成为垃圾空间(字符串常量 "hello"也是一个匿名对象, 用了一次之后就不再使用了, 就成为垃圾空间, 会被 JVM 自动回收掉).
  2. 字符串共享问题. 同一个字符串可能会被存储多次, 比较浪费空间

我们可以使用 String 的 intern 方法来手动把 String 对象加入到字符串常量池中

// 该字符串常量并没有保存在对象池之中
String str1 = new String("hello") ;
String str2 = "hello" ;
System.out.println(str1 == str2);
// 执行结果
false
String str1 = new String("hello").intern() ;
String str2 = "hello" ;
System.out.println(str1 == str2);
// 执行结果
true

在这里插入图片描述

字符串是不可变的

字符串是一种不可变对象,它的内容不可以改变。

String str = "hello" ;
str = str + " world" ;
str += "!!!" ;
System.out.println(str);
// 执行结果
hello world!!!

上述代码,内存表现,看起来改变了,实际未改变。
在这里插入图片描述

综上所述,String因为是不可变对象,所以在定义好一个String对象之后,String的值就不能改变,如果显示改变,改变的只有指向的链接而已。对于String对象的这一特点,就有了StringBuffer和StringBuilder这两个类,他们可以针对字符串进行修改。

StringBuilder 和 StringBuffer

  从上面我们知道这两个类的相对于String最大特点是可以进行对字符串的修改。因为这两个类的功能大部分是相同的,所以我们在相同点上主要以StringBuffer为主介绍。

名称作用
reverse()字符串反转
delete(int start,int end)删除指定范围的数据
insert(int offset ,各种数据类型 b)插入数据
append(各种数据类型 b )字符串连接

StringBuffer 示例使用:

public class Main {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer();
        sb.append("我的").append("博客");
        fun(sb);
        System.out.println(sb);
    }
    public static void fun(StringBuffer temp) {
        temp.append("\n").append("https://blog.csdn.net/qq_44923467");
    }
}
StringBuffer与StringBuilder的不同

  先看看StringBuffer和StringBuilder的继承关系。从下图我们可以看出两个都继承了AbstractStringBuilder这个抽象类,实现了CharSequence接口。CharSequence接口描述的就是一系列的字符集,所以字符串是字符集的子类。

  • StringBuffer的继承关系
    在这里插入图片描述
  • StringBuilder的继承关系
    在这里插入图片描述

StringBuffer与StringBuilder不同的是StringBuffer中里面的操作方法都用synchornized来进行修饰,所以我们说StringBuffer是安全的。也正因如此,synchronized获取锁释放锁也还是需要时间的,所以StringBuffer适用于并发量并不是很高的场景下。

在这里插入图片描述
StringBuilder没有加任何锁,但是效率高,适用于单线程场景,但同时也适用于高并发场景中,提高高并发场景下程序的响应性能。

面试题

  • 请解释String类中两种对象实例化的区别
    1. 直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用。
    2. 构造方法:会开辟两块堆内存空间,其中一块成为垃圾空间,不会自动保存在对象池中,可以使用intern()方法手工入池。
  • 请解释String、StringBuffer、StringBuilder的区别:
    1. String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
    2. StringBuffer与StringBuilder大部分功能是相似的
    3. StringBuffer采用同步处理,属于线程安全操作;而StringBuilder采用异步处理,属于线程不安全操作。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值