知识回顾:八大基本数据类型

数据类型 大小
byte(字节) 1(8位)
short(短整型) 2(16位)
int(整形) 4(32位)
long(长整型) 8(64位)
float(浮点型) 4(32位)
double(双精度) 8(63位)
char(字符型) 2(16位)
boolean(布尔型) 1位

概述

字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。String是每个java程序员几乎每天都要用到的类,我们先来看一下源码。

在这里插入图片描述
从String的源码中我们看到String本质上就是一个char类型的数组,数组中的每个字符串拼接起来就形成了一个字符串,而且它用final关键字修饰的。

另外一个属性就是hash,它保存的是value的hash值。

String为什么用final修饰呢

对于final这个关键字相信大家都很熟悉,用final修饰的类无法继承;用final修饰的方法无法被被重写的;用final修饰的变量是无法被修改的;所以很多人就此得出一个结论:String是不可变类型,其实这是不对的。String确实是不可变类型,但不仅仅是因为它是被final修饰所导致的

在这里插入图片描述
首先我们要理解final真正的含义,final修饰class该类是不可以被继承,这个是没有问题的,final修饰变量的时候,如果变量是八大基本数据类型的话它的值无法被修改是没有问题的,如果是引用类型的话,那仅仅是它的引用地址无法被改变,而内存地址上的值是可以被改变的。

如下面代码,把第一元素改成d,然后我们输出结果
在这里插入图片描述
我们确实了引用对象上的值
我们确实了引用对象上的值。

那么String之所以是不可变类型,更重要的其实内部开发者对value数组的权限控制,以及每次操作过程中保护的value的值,在每一次对字符串进行操作时,都不是在原有的value数组上进行改动的,而是生成了一个新的value数组。

String为什么设计成不可变类型

因为String在Java中除了基本类型之外,最常用的一种类型,几乎每一个类都需要用到String,java之所以把String设计成不可变类型。我们可以理解为在逻辑上string等价于八大基本数据类型,但是基本数据类型是值对象,String是引用对象,可能是由于某些特殊的历史原因和考量,String最终没有成为java的基本类型之一。这个理由是可以得到验证的,比如跟java最相似的C#语言,它的String就是基本类型,那么String为什么要被设计成不可变的类型呢?它最主要优点就在于效率和安全!主要可以体现在以下几个方面:

1.它无法被继承

它的私有方法无法被重写,这就意味着带String类型参数的方法,都只能传入String类型的引用,而不能传入String子类型的引用,这就能够保持语义的统一。

2.每次操作生成新对象

在这里插入图片描述

比如有两个引用a和b,指向同一个String对象c,a改变了c对象的值,结果引用b来取值发现和预期的值不一样,为了杜绝这种情况,每次对string进行操作都会生成一个新的string对象,比如引用a对string对象c1进行了操作,会产生新的string对象c1 ,Java为什么要这样设计呢,我们可以理解是对程序员的一种不信任或者说是对程序员的一种服务,因为人太容易出错了,尤其是像string这种最常见的类型,只要程序员稍微一出错就很有可能造成大错.

3.从线程安全角度出发

因为String是不可变的,多个线程无法修改同一个String,那么就无法形成竞态条件,所以就一定保证线程的安全。

String常量池

在这里插入图片描述
首先我们先来看下以下的代码

String a="123";
String b="123";
String c=new String("123");
String d=new String("123");
System.out.println(a==b); //true
System.out.println(b==c); //false
System.out.println(c==d);//false

这是就要引出一个String常量池的概念,String常量池为Java内存模型中的方法区,一部分是经过编译期加入的,一部分是运行时加入的,主要是因为字符串的创建是一个非常高频的操作,创建String对象的时候,如果发现常量池中存在值一样的字符串,那么可以直接返回实例。而且常量池中的对象不会轻易地的被垃圾回收,这样就能减少很多开销。回头看上面的题目是很简单了,引用a和引用b是编译期就进入常量池的,所以他们指向的是同一个字符串对象。

引用c和引用d是在运行的时候指向各自在堆上创建的对象,所以这道题就判断引用指向对象是否相同。

String、StringBuilder和StringBuffer的区别

String是不可变类型,但是它的特点造成了一个缺点,假如在循环中构造一个字符串,如果使用String字符串那么将会创建的对象,又假如如果在业务中频繁打印日志,打印一条日志的时候需要拼接大量的字符串也会造成大量的String对象,这无疑是对内存和垃圾回收造成很大的压力。

StringBuilder和StringBuffer它们两个的存在主要是为了更加优雅地构造字符串,能够产生一个可变的字符串序列,然后这个序列是可以被修改的,在一系列的修改之后,它只会产生一个字符串对象,这样就会非常节省资源。

那值得一提的就是StringBuilder是线程不安全的,所以它的效率会更高一点,而StringBuffer是线程安全的,那它内部是会做了一些同步的操作,它会允许多个线程对String字符串进行修改,所以的效率是会低一些的。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐