StringTable的概念、hashcode()、equals的区别与联系、String、StringBuffer、StringBuilder区别、ArrayList 和 LinkedList

StringTable

String table又称为String pool,字符串常量池,其存在于堆中,不过这是从1.7版本开始的,1.7之前保存在永久代中。最重要的一点,String table中存储的并不是String类型的对象,存储的而是指向String对象的索引,真实对象还是存储在堆中。
此外String table还存在一个hash表的特性,里面不存在相同的两个字符串。
StringTable的底层数据结构是HashTable,每个元素都是key-value结构,采用了数组+单向链表的实现方式。

此外String对象调用intern()方法时,会先在String table中查找是否存在于该对象相同的字符串,若存在直接返回String table中字符串的引用,若不存在则在String table中创建一个与该对象相同的字符串。

当我们使用new String()去创建一个字符串对象时和直接写String a = "hello"是不一样的。
前者保存在堆内存中,后者保存在StringTable(也是在堆内存空间中的)中。
如下图:
在这里插入图片描述

package stringtable;

public class Demo1 {
    public static void main(String[] args) {
        String s1 = "a";
        String s2 = "b";
        String s3 = "a" + "b"; //s3(ab)存于StringTable中
        /**
         * new StringBuilder().append("a").append("b").toString() : new String("ab")
         * 因为toString()操作有一个new的过程,因此,s4存放在堆内存中
         */
        String s4 = s1 + s2; //两个字符串变量的拼接,最后有一个new StringBuilder()的过程,s4存于堆内存中
        String s5 = "ab"; //ab已经存放在方法区的StringTable中
        String s6 = s4.intern(); //intern()方法尝试将字符串对象放入StringTable中,若存在不会放入,反之放入。并返回字符串对象的规范化表示形式

        //说明s3、s5指向的是同一个StringTable中的常量ab
        System.out.println(s3.hashCode() == s5.hashCode());
        System.out.println(s3.equals(s5)+"\n------------");

        System.out.println(s3 == s4); //false
        System.out.println(s3 == s5); //true
        System.out.println(s3 == s6); //true
        System.out.println(s4 == s5); //false
        System.out.println("------------");

        /**
         * ==运算符是判断两个对象是不是同一个对象,即他们的地址是否相等
         * object类中equals与==是等效的
         * 覆写equals更多的是追求两个对象在逻辑上的相等,你可以说是值相等,也可说是内容相等。(覆盖以后,覆盖equals时总要覆盖hashCode)
         * hashCode用于返回对象的hash值,主要用于查找的快捷性,因为hashCode也是在Object对象中就有的,所以所有Java对象都有hashCode,
         * 在HashTable和HashMap这一类的散列结构中,都是通过hashCode来查找在散列表中的位置的。
         */
        System.out.println(s4+" : "+s6);
        System.out.println(s4 == s6); //false
        System.out.println(s4.hashCode() == s6.hashCode());
        System.out.println(s4.equals(s6)+"\n------------");

        String x2 = new String("c") + new String("d"); //x2 = "ab" 存于堆中
        String x1 = "cd"; //存于方法区的StringTable中
        String x3 = x2.intern(); //存于方法区的StringTable中

        System.out.println(x1 == x2); //false
        System.out.println(x1 == x3); //true
        System.out.println(x2 == x3); //false
    }
}

运行结果:
在这里插入图片描述

hashcode()和equals

在这里插入图片描述
如上图所示:
equals()代表数组下标链表中的元素索引、hashcode()代表数组下标和所链接链表代表的索引,因此hashcode相等的元素可能不止一个。

equals相等的两个对象,hashCode一定相等
equals方法不相等的两个对象,hashCode有可能相等
在每个覆盖了equals方法的类中,也必须覆盖hashCode方法,如果不这样做的话,就会违反Object.hashCode的通用约定。从而导致该类无法结合所有基于散列的集合一起正常运作。

String、StringBuffer、StringBuilder

可变性

String对象是不可变的。StringBuilder与StringBuffer这两种对象都是可变的。

线程安全性

String中的对象是不可变的,也就可以理解为常量,线程安全。
StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。
StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。

性能

每次对String 类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String 对象。
StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。
相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。

对于三者使用的总结

如果要操作少量的数据用 = String
单线程操作字符串缓冲区下操作大量数据 = StringBuilder
多线程操作字符串缓冲区下操作大量数据 = StringBuffer

ArrayList 和 LinkedList 的区别是什么?

在这里插入图片描述

数据结构实现

ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实现。

随机访问效率

ArrayList 比 LinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数据存储方式,所以需要移动指针从前往后依次查找。
增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为 ArrayList 增删操作要影响数组内的其他数据的下标。

内存空间占用

LinkedList 比 ArrayList 更占内存,因为 LinkedList 的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。
线程安全:ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
综合来说,在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推荐使用 LinkedList。

补充:数据结构基础之双向链表

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值