美文网首页
Java专题之String

Java专题之String

作者: 这一刻_776b | 来源:发表于2019-12-30 14:29 被阅读0次

一、String简介

1.1 String是不可变对象

java.lang.String类使用了final修饰,不能被继承。Java程序中的所有字面值,即双引号括起的字符串,如"abc",都是作为String类的实例实现的。String是常量,其对象一旦构造就不能再被改变。换句话说,String对象是不可变的,每一个看起来会修改String值的方法。

1.2 String的构成

public final class String

2    implements java.io.Serializable, Comparable<String>, CharSequence {

3    /** The value is used for character storage. */

4    private final char value[];

5

6    /** Cache the hash code for the string */

7    private int hash; // Default to 0

通过源码我们可以知道String底层是由char 数组构成的,我们创建一个字符串对象的时候,其实是将字符串保存在char数组中,因为数组是引用对象,为了防止数组可变,jdk加了final修饰,加了final修饰的数组只是代表了引用不可变,不代表数组的内容不可变,因此jdk为了真正防止不可变,又加了一个private修饰符。

说到String不得不提字符串常量池,这个常量池主要存储在方法区中,当一个字符串被创建的时候,首先会去常量池中查找,如果找到了就返回对改字符串的引用,如果没找到就创建这个字符串并塞到常量池中。

1.3什么是不可变?

(1)其状态不能在创建后再修改;

(2)所有域都是final类型;

(3)其构造函数构造对象期间,this引用没有泄露。

1.4 不可变带来的好处

一、安全性

(1)多线程安全性

因为String是不可变的,因此在多线程操作下,它是安全的,我们看下如下代码:

1public String get(String str){

2  str +="aaa";

3  return str;

4}

试想一下如果String是可变的,那么get方法内部改变了str的值,方法外部str也会随之改变。

(2)类加载中体现的安全性

类加载器要用到字符串,不可变性提供了安全性,以便正确的类被加载。譬如你想加载java.sql.Connection类,而这个值被改成了hacked.Connection,那么会对你的数据库造成不可知的破坏。

二、使用常量池节省空间

只有当字符串是不可变的,字符串池才有可能实现。字符串池的实现可以在运行时节约很多heap空间,因为不同的字符串变量都指向池中的同一个字符串。但如果字符串是可变的,那么String interning将不能实现(String interning是指对不同的字符串仅仅只保存一个,即不会保存多个相同的字符串),因为这样的话,如果变量改变了它的值,那么其它指向这个值的变量的值也会一起改变。

三、缓存hashcode

因为字符串是不可变的,所以在它创建的时候hashcode就被缓存了,不需要重新计算。这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串。

我们可以看到String中有如下代码:

1private int hash;//this is used to cache hash code.

以上代码中hash变量中就保存了一个String对象的hashcode,因为String类不可变,所以一旦对象被创建,该hash值也无法改变。所以,每次想要使用该对象的hashcode的时候,直接返回即可。

1.5不可变带来的缺点

不可变对象也有一个缺点就是会制造大量垃圾,由于他们不能被重用而且对于它们的使用就是”用“然后”扔“,字符串就是一个典型的例子,它会创造很多的垃圾,给垃圾收集带来很大的麻烦。当然这只是个极端的例子,合理的使用不可变对象会创造很大的价值。

密码应该存放在字符数组中而不是String中

由于String在Java中是不可变的,如果你将密码以明文的形式保存成字符串,那么它将一直留在内存中,直到垃圾收集器把它清除。而由于字符串被放在字符串缓冲池中以方便重复使用,所以它就可能在内存中被保留很长时间,而这将导致安全隐患,因为任何能够访问内存(memory dump内存转储)的人都能清晰的看到文本中的密码,这也是为什么你应该总是使用加密的形式而不是明文来保存密码。由于字符串是不可变的,所以没有任何方式可以修改字符串的值,因为每次修改都将产生新的字符串,然而如果你使用char[]来保存密码,你仍然可以将其中所有的元素都设置为空或者零。所以将密码保存到字符数组中很明显的降低了密码被窃取的风险。

当然只使用字符数组也是不够的,为了更安全你需要将数组内容进行转化。建议使用哈希的或者是加密过的密码而不是明文,然后一旦完成验证,就将它从内存中清除掉。

1.6 String,StringBuilder,StringBuffer三者的区别

(1)首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String

String最慢的原因:String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。

(2)再来说线程安全。在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的

(3)总结一下String:适用于少量的字符串操作的情况

StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况

StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况

相关文章

网友评论

      本文标题:Java专题之String

      本文链接:https://www.haomeiwen.com/subject/oacmoctx.html