String 被声明为 final,因此它不可被继承。(Integer 等包装类也不能被继承) 在java8中,String内部以char[]数组的形式存储数据;
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[];String 常见的创建方式:
String s1 = “java”; 从String pool寻找,返回句柄String s2 = new String(“java”)第一种方式,从String pool寻找java,没有则在pool中创建,返回句柄; 第二种方式,会直接在堆(1.7后)创建String对象,只有调用了intern()方法,才会放入String pool; [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SYCt7EBY-1593684383098)(/home/picture/1.png)] JDK 1.7 之后把永生代换成的元空间,把字符串常量池从方法区移到了 Java 堆上。 除此之外编译器还会对String字符串做一些优化:
String s1 = "ja"+"va"; String s2 = "java"; System.out.pringln(s1 == s2); //结果为truevalue数组被生命成了final,意味着value一旦初始化后便不可指向其它内存地址,并且String内部,没有改变value内容的任何方法。且String类为final类,避免了子类重写或修改String对象属性; 保护性拷贝:
public String(char value[]) { this.value = Arrays.copyOf(value, value.length); }这是以char数组为参数的一个构造方法,它并没有把这个数组引用直接赋值给实例对象的value成员变量,而是通过一个Arrays.copyOf的方式拷贝一个数组再给到对象的成员变量,防止外部引用执行同一个地址而修改该数组内容。
如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。 以下代码将在堆中仅创建一个字符串对象。
字符串 string1 = “ abcd” ; 字符串 string2 = “ abcd” ;[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X4Nu5xMj-1593684383101)(/home/picture/1.png)]
字符串的哈希码在Java中经常使用。例如,在HashMap或HashSet中。不可变保证哈希码始终是相同的,这意味着无需每次使用哈希码就进行计算,这样更有效。
字符串被广泛用作许多java类的参数,例如网络连接,打开文件等。如果字符串不是不可变的,则连接或文件将被更改,这可能会导致严重的安全威胁,可变字符串也可能在反射中引起安全问题。
String 不可变性天生具备线程安全,可以在多个线程中安全地使用。
字符串常量池保存着所有字符串字面量,这些字面量在编译时期就确定。不仅如此,还可以使用 String 的 intern() 方法在运行过程将字符串添加到 String Pool 中。 主要使用方式:
直接使用双引号声明出来的String对象会直接存储在常量池中。如果不是用双引号声明的String对象,可以使用String提供的intern方法。intern 方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中 String s1 = "aaa"; String s2 = "aaa"; System.out.println(s1 == s2); // true如果采用"aaa"这种字面量的形式创建字符串,会自动地将字符串放入 String Pool 中。 intern() 方法:当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定),那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。
它的大体实现结构就是: JAVA 使用 jni 调用c++实现的StringTable的intern方法, StringTable的intern方法跟Java中的HashMap的实现是差不多的, 只是不能自动扩容。默认大小是1009。 要注意的是,String的String Pool是一个固定大小的Hashtable,默认值大小长度是1009,如果放进String Pool的String非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了后直接会造成的影响就是当调用String.intern时性能会大幅下降(因为要一个一个找)。
在 jdk6中StringTable是固定的,就是1009的长度,所以如果常量池中的字符串过多就会导致效率下降很快。在jdk7中,StringTable的长度可以通过一个参数指定:
-XX:StringTableSize=99991
new String(“abc”) 上述的语句中是创建了2个对象,第一个对象是”abc”字符串存储在常量池中,第二个对象在JAVA Heap中的 String 对象。
1. 可变性 String 不可变 StringBuffer 和 StringBuilder 可变 2. 线程安全 String 不可变,因此是线程安全的 StringBuilder 不是线程安全的 StringBuffer 是线程安全的,内部使用 synchronized 进行同步
1. equals() 用于比较两个字符串是否相等,比较时会先通过instanceof 判断是否为String类型,如果不是直接反悔false,否则循环比较每一个字符
