Java基础知识整理

一、集合 

数组和集合比较

1.  数组能存放基本数据类型和对象,而集合类存放的都是对象,集合类不能存放基本数据类型。数组和集合存放的对象皆为对象的引用地址。
2.  数组容易固定无法动态改变,集合类容量动态改变。
3.  数组无法判断其中实际存有多少元素,length只告诉了数组的容量,而集合的size()可以确切知道元素的个数。
4.  集合有多种实现方式和不同适用场合,不像数组仅采用顺序表方式。
5.  集合以类的形式存在,具有封装、继承、多态等类的特性,通过简单的方法和属性即可实现各种复杂操作,大大提高了软件的开发效率。

1.1 List

List表达一个有序集合,每个元素都有索引,能够使用索引来访问List中的元素。
ArrayList:底层数据结构是一个数组,查询通过下标,查询速度快,增删慢,线程不安全。
LinkedList:  底层数据结构是链表,插入、删除只需要改变节点的指针指向,所以增删元素快,查询慢,线程不安全。
使用场景:当需要对数据进行访问的情况下选用ArrayList, 需要对数据进行多次增加删除修改时采用LinkedList。

1.2 Set

Set接口的特点是不能包含重复的元素,Set最多有一个null元素。
HashSet: 底层结构采用哈希表实现,元素无序且唯一,线程不安全,效率高,可存储null元素。
TreeSet:底层数据结构采用红黑树来实现,元素唯一且已经排好序;唯一性同样需要重写hashCode和equals()方法。
LinkedHashSet: 它是HashSet的子类,底层结构链表+哈希表,是一个双链链表。链表保证元素的添加顺序,哈希表保证元素的唯一性。是按照添加元素的顺序存储。
适用场景:HashSet是基于Hash算法实现的,性能通常优于TreeSet。需要排序时采用TreeSet。
HashSet如何保证元素唯一:调用对象的hashCode()方法得到一个哈希值,  然后在集合中查找是否有哈希值相同的对象。(逐个调用equals()方法效率低) 如果没有哈希值相同的对象就直接存入集合,如果有哈希值相同的对象, 就和哈希值相同的对象逐个进行equals()比较,比较结果为false就存入, true则不存。

1.3 Map

HashMap:key值可以为null,  value值可以为null, 线程不安全。
LinkedHashMap: 用链表实现来扩展HashMap类,HashMap是没有顺序的, LinkedHashMap可以按照它们插入的顺序排序。
TreeMap:  key值不可以为null, value可以为null。 基于红黑树数据结构实现,可以排序。
HashMap的底层实现: HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的。put时调用key.hashCode()方法,找到数组位置,存储Entry对象。get时通过hashCode找到数组位置,如果此位置有多个key,用key.equal()方法遍历链表找到值对象。1.8以后如果元素不超过8个用链表,超过8个且元素数量大于64则转为红黑树。
resize:  当HashMap中的元素越来越多时,Hash冲突的几率越高。为了提高查询效率,当数组中的元素个数超过数组大小*loadFactor时, 就会对数据进行扩容。默认情况下数组大小为16, loadFactor为0.75,那么当hashmap中的元素个数超过16*0.75=12时, 就会扩容为16*2=32, 扩大一倍。数组扩容过程中会重新计算hash, 是一个很耗性能的操作,尽量在初始化时预估预算的最大容量。
 
为什么重写equal()要重写hashcode()方法? 
答:提升性能, 如Set集合中是先比较hashcode再做equal比较。
实体类重写equal例子:
public boolean equals(Object obj){
    if(obj == null){
        return false;
    }
        
    //如果是同一个对象返回true,反之返回false
    if(this == obj){
        return true;
    }
        
    //判断是否类型相同
    if(this.getClass() != obj.getClass()){
        return false;
    }
        
    User user = (User)obj;
    return userName.equals(user.userName) && password.equals(user.password);
}

1.4 ConcurrentHashMap

key值不能为null, value不能为null。HashMap线程不安全,put时可能会导致数据不一致。resize时可能会造成环形链表,也就是死循环。 ConcurrentHashMap是线程安全的。
原理:JDK1.7采用segment的分段锁机制实现线程安全,其中segment继承自ReentrantLock,结构时Segment + HashEntry数组 + HashEntry链表。JDK1.8去掉了segment, 采用CAS + Synchronized + volatile保证线程安全。结构是数组+链表,如果链表长度大于某个阀值,会转成红黑树。
1.8源码剖析 https://blog.csdn.net/jy02268879/article/details/88599830
posted on 2021-03-25 17:24  lvguoliang(学无止境)  阅读(41)  评论(0编辑  收藏  举报