理解、总结重点知识

一、常见的数据结构
1、数组结构
数组结构: 存储区间连续、内存占用严重、空间复杂度大

  • 优点:随机读取和修改效率高,原因是数组是连续的(随机访问性强,查找速度快)
  • 缺点:插入和删除数据效率低,因插入数据,这个位置后面的数据在内存中都要往后移动,且大小固定不易动态扩展。

2、链表结构
存储区间离散、占用内存宽松、空间复杂度小

  • 优点:插入删除速度快,内存利用率高,没有固定大小,扩展灵活
  • 缺点:不能随机查找,每次都是从第一个开始遍历(查询效率低)

3、哈希表结构

  • 特点:结合数组结构和链表结构的优点,从而实现了查询和修改效率高,插入和删除效率也高的一种数据结构

二、List集合 底层实现原理
1、ArrayList
本质是数组,具有自动扩容,默认长度10,当插入数据大于了当前长度,重新创建新数组,长度为旧数组长度的1.5倍,并将所有数据复制到新数组中,释放旧数组。

  • 优点:按顺序添加,查询快,通过下标找出某一个值
  • 缺点:删除和插入比较耗时,删除一个整体需要向前移动一位,添加一个整体需要向后移动一位,

2、LinkedList
和List集合用法一样线程不安全

  • 优点:插入和删除快,LinkedList集合实现双向链表接口,实现从头元素到尾元素的链表和从尾到头元素的链表,目标为了增加元素的检索效率
    ,适合做随机的增加或者删除
  • 缺点:查询慢,

3、Voctor

  • 线程安全 Vector中所有的方法都是线程同步的,都带有synchronized关键字,所以他的并行性能慢,不建议使用

三、map底层实现原理
HashMap实现原理,底层是使用哈希表的方式实现
1、map.put(k,v)
(1)将k,v封装到Node对象当中(节点)。
(2)然后它的底层会调用K的hashCode()方法得出hash值。
(3)通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着k和链表上每个节点的k进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。
2、map.get(k)
(1)调用k的hashCode()方法得出哈希值,并通过哈希算法转换成数组的下标。
(2)通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上。如果这个位置上什么都没有,则返回null。如果这个位置上有单向链表,那么它就会拿着K和单向链表上的每一个节点的K进行equals,如果所有equals方法都返回false,则get方法返回null。如果其中一个节点的K和参数K进行equals返回true,那么此时该节点的value就是我们要找的value了,get方法最终返回这个要找的value。
2、HashSet

  • 基于HashMap实现的,默认构造函数是构建一个初始容量为16,负载因子为0.75 的HashMap。封装了一个 HashMap
    对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的
    value 则存储了一个 PRESENT,它是一个静态的 Object 对象。

HashSet源码构造器中实例化一个HashMap

 /**
     * Constructs a new set containing the elements in the specified
     * collection.  The HashMap is created with default load factor
     * (0.75) and an initial capacity sufficient to contain the elements in
     * the specified collection.
     *
     * @param c the collection whose elements are to be placed into this set
     * @throws NullPointerException if the specified collection is null
     */
    public HashSet(Collection c) {
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
    }

四、字符串
1、String
特性

  • String是被final修饰的类,不能被继承;
  • String实现了Serializable和Comparable接口,表示String支持序列化和可以比较大小;
  • String底层是通过char类型的数据实现的,并且被final修饰,所以字符串的值创建之后就不可以被修改,具有不可变性。

不可变性

举例,s1和s2的值相同同时指向同一个内存地址address1,如果将s1从新赋值,那么并不是在原来的内存地址address1修改内容的,而是重新分配一个新的内存地址address2。

String s1="测试";
String s2="测试";
s1="hello";

String实例化
1、方式一 :字符串存储在方法区的字符串常量池中

String text = "sss"

2、方式二:字符串对象存储在堆中,但是字符串的值仍然存储在方法区的常量池中

String text1 = new String("sss")

2、StringBuffer 和StringBuilder深层理解

  • StringBuffer、StringBuilder和String类似,底层也是用一个数组来存储字符串的值,并且数组的默认长度为16,即一个空的StringBuffer对象数组长度为16。实例化一个StringBuffer对象即创建了一个大小为16个字符的字符串缓冲区。但是​当我们调用有参构造函数创建一个StringBuffer对象时,数组长度就不再是16了,而是根据当前对象的值来决定数组的长度,数组的长度为“当前对象的值的长+16”。所以一个
    StringBuffer 创建完成之后,有16个字符的空间可以对其值进行修改。如果修改的值范围超出了16个字符,会先检查StringBuffer对象的原char数组的容量能不能装下新的字符串,如果装不下则会对char 数组进行扩容。
  • 那StringBuffer是怎样进行扩容的呢? 扩容的逻辑就是创建一个新的 char,数组将现有容量扩大一倍再加上2,如果还是不够大则直接等于需要的容量大小。扩容完成之后,将原数组的内容复制到新数组,最后将指针指向新的 char 数组。
  • String、StringBuffer和StringBuilder的异同?
    (1)相同点:底层都是通过char数组实现的
    (2)不同点:String对象一旦创建,其值是不能修改的,如果要修改,会重新开辟内存空间来存储修改之后的对象;而StringBuffer和StringBuilder对象的值是可以被修改的;
    StringBuffer几乎所有的方法都使用synchronized实现了同步,线程比较安全,在多线程系统中可以保证数据同步,但是效率比较低;而StringBuilder 没有实现同步,线程不安全,在多线程系统中不能使用 StringBuilder,但是效率比较高。
    如果我们在实际开发过程中需要对字符串进行频繁的修改,不要使用String,否则会造成内存空间的浪费;当需要考虑线程安全的场景下使用 StringBuffer,如果不需要考虑线程安全,追求效率的场景下可以使用 StringBuilder。

3、SpannableString、SpannableStringBuilder与String

  • 首先SpannableString、SpannableStringBuilder基本上与String差不多,也是用来存储字符串,但它们俩的特殊就在于有一个SetSpan()函数,能给这些存储的String添加各种格式或者称样式(Span),将原来的String以不同的样式显示出来,比如在原来String上加下划线、加背景色、改变字体颜色、用图片把指定的文字给替换掉,等等。所以,总而言之,SpannableString、SpannableStringBuilder与String一样,也是传字符串,但SpannableString、SpannableStringBuilder可以对这些字符串添加额外的样式信息,但String则不行。

4、SpannableString、SpannableStringBuilder

  • 它们的区别在于 SpannableString像一个String一样,构造对象的时候传入一个String,之后再无法更改String的内容,也无法拼接多个 SpannableString;而SpannableStringBuilder则更像是StringBuilder,它可以通过其append()方法来拼接多个String:
//使用SpannableString,必须一次传入,构造完成
SpannableString word = new SpannableString("abc");
 
//使用SpannableStringBuilder,可以使用append()再添加
SpannableStringBuilder multiWord = new SpannableStringBuilder();
multiWord.append("a");
multiWord.append("b");
multiWord.append("c");

你可能感兴趣的:(工作笔记,java)