集合笔记

集合

数组。 存储相同数据类型的数据, 可以基本+引用。 容器: 存储(新增)+查看 底层数据结构。

优点:
  查询速度最快, index
  修改  
弊端:
  新增元素  数组大小是一定的  手动扩容  Arrays.copyOf()
  删除元素  元素数据都是连贯  手动移动位置    

集合。 容器。 自动扩容,移动位置。 理论上集合可以存储不同引用数据类型的数据。Object

真实使用上,存储相同类型的数据。 (泛型)

1. Collection

存储单列元素。没有索引位置

泛型的标识: <> A-Z: 参数化类型 (可以是任意的引用数据类型)

public interface Collection<E> extends Iterable<E>
public interface Iterable<T>: 遍历集合元素
Iterator<T> iterator()  获得集合对象的迭代器对象(集合的所有的元素都在Iterator里面)
    Iterator:
         boolean hasNext() : 判断光标之后是否有更多的元素需要遍历 
         E next() : 获得光标之后元素数据 
         default void remove() : 删除元素
             
default void forEach(Consumer<? super T> action)  使用lamda遍历集合所有的元素
boolean add(E e)  新增一个元素
void clear()  
    
boolean contains(Object o)  
boolean isEmpty()  
boolean remove(Object o)  删除指定元素
int size()  
    
Object[] toArray()  
<T> T[] toArray(T[] a)  
    
default Stream<E> parallelStream()
default Stream<E> stream()  对集合元素执行操作
default boolean removeIf(Predicate<? super E> filter)  删除多个满足条件元素

遍历方式

//遍历: 循环遍历集合元素  1.1. 增强for循环
//        for (Object obj : collection) {
            if (Objects.equals(100, obj)) {
                collection.remove(obj);
            }
//            System.out.println(obj);
//        }
//  1.2  使用Iterator执行遍历(可以遍历期间删除)
       /* Iterator iterator = collection.iterator();
        //获得集合对象的的迭代器对象  集合的所有元素都在iterator
        //判断光标之后有没有元素需要遍历
        while (iterator.hasNext()) {
            Object element = iterator.next();
//            System.out.println(element);
            if(Objects.equals(element,100)){
//                collection.remove(element);
                iterator.remove();
            }
        }*/
 //1.3  forEach方法
//        collection.forEach(new Consumer() {
//            @Override
//            public void accept(Object obj) {
//                //obj 就是集合所有的元素了
//                System.out.println(obj);
//            }
//        });

//        collection.forEach(obj->{
//            System.out.println(obj);
//        });
        //单纯测试:遍历
//        collection.forEach(System.out::println);

1.1 List

元素是否重复元素是否有索引位置
List可以都有索引
Set唯一没有索引
void add(int index, E element)   指定索引位置
E get(int index)  
E remove(int index)  
ListIterator<E> listIterator() 
E set(int index, E element)  
List<E> subList(int fromIndex, int toIndex)  

集合: 存储 (数据从哪里来? 从数据库里面查询的) 遍历

底层数据结构功能效率线程安全
CopyOnWriteArrayList动态数组都慢线程安全
ArrayList动态数组查询不安全
LinkedList双向链表新增 删除不安全
vector动态数组都慢线程安全
1.1.1ArrayList
public class ArrayList<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable

RandomAccess: 标识接口 可以支持快速访问。普通for循环比迭代器的效率还要快。

ArrayList()  构造一个初始容量为十的空数组。 
ArrayList(int initialCapacity) 
ArrayList(Collection<? extends E> c) 
 public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
 transient Object[] elementData; // non-private to simplify nested class access
//集合的元素数据都在: elementData
 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
private int size; //统计集合元素个数
public boolean add(E e) {
        ensureCapacityInternal(size + 1);  //判断底层数组空间容量是否足够
        elementData[size++] = e;// elementData[0] = e
        return true;
    }

 private void ensureCapacityInternal(int minCapacity) {//1
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

private static final int DEFAULT_CAPACITY = 10;//初始化数组容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {//{}  1
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);//
        }
        return minCapacity;
    }
private void ensureExplicitCapacity(int minCapacity) {//10
        modCount++;// 新增  删除    维护操作集合元素的次数

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);//扩容
    }
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;//0
        int newCapacity = oldCapacity + (oldCapacity >> 1);//0   1.5倍增长
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;//10
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);// 扩容
  }
1.1.2 LinkedList
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, Serializable
链表:
  1.单向链表 
     当前数据会记得下一个数据的引用 next 当前数据  data
 
  2.双向链表
    当前数据会记得下一个数据的引用 next 还会记得上一个数据previous的引用  当前数据  item

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rc48wAll-1605082245767)(pic\LinkedList .png)]

栈: filo  先进后出
队列: FIFO  先进先出
LinkedList() 
transient Node<E> last;//null
void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);//(null,100,null)
        last = newNode;//last = 100的引用
        if (l == null)
            first = newNode;// transient Node<E> first; = (null,100,null)
        else
            l.next = newNode;
        size++;
        modCount++;
    }

//双向链表
private static class Node<E> {
        E item;//当前元素数据
        Node<E> next;//下一个引用
        Node<E> prev;//上一个引用

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

 Node<E> node(int index) {
        // assert isElementIndex(index);

        if (index < (size >> 1)) {// 将整个LinkedList的数据  划分成左右2个部分 进行寻找
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }
1.1.3 CopyOnWriteArrayList

线程安全,

1.2 Set

元素唯一的 不可重复的 元素没有索引位置的。

数据结构元素是否可以为null线程安全
HashSetHashMap维护可以
LinkedHashSet哈希表+链表LinkedHashMap可以
TreeSet红黑树 TreeMap不可以
CopyOnWriteArraySet可以
1.2.1 HashSet
HashSet(int initialCapacity) 
1.2.2 LinkedHashSet
1.2.3 TreeSet

2. Map<K,V>

存储的一组元素。键值对 key—value key: 元素都是唯一的 value: 是可以重复的

static interface  Map.Entry<K,V>  内部接口  代表map集合里面每组元素数据  称为键值对
boolean isEmpty()  
V put(K key, V value)  新增map集合元素
V get(Object key)  根据key获得value

default V replace(K key, V value)  修改指定的key所对应的value
default boolean replace(K key, V oldValue, V newValue)  
    
V remove(Object key)  删除指定key
default boolean remove(Object key, Object value)  
int size()  
void clear()  
boolean containsKey(Object key) 
boolean containsValue(Object value)  
    
Set<Map.Entry<K,V>> entrySet()  获得map集合里面所有的键值对
default void forEach(BiConsumer<? super K,? super V> action)  
Set<K> keySet()  获得map所有的key
Collection<V> values()  获得map所有的value

常用实现类以及区别

底层数据结构K,V是否可以为null线程安全
HashMap<K,V>数组(位桶)+链表+红黑树KV都可以null
LinkedHashMap<K,V>哈希表+链表KV都可以null
TreeMap<K,V>红黑树K不能为null V可以
HashTable<K,V>哈希表KV都不可以null是 同步
ConcurrentHashMap<K,V>哈希表KV都不可以null是 CAS: Redis 查询多

2.1 HashMap<K,V>

HashMap(int initialCapacity)   initialCapacity= 存储元素个数/负载因子+1
HashMap() 默认初始容量(16)和默认负载系数(0.75)。 
static final float DEFAULT_LOAD_FACTOR = 0.75f;
public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }

  public V put(K key, V value) {// 1  100
        return putVal(hash(key), key, value, false, true);
    }//putVal(1,1,100,flase,true)

//计算map的key的hash (更加具有随机性  避免hash碰撞)
static final int hash(Object key) {//1
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

  transient Node<K,V>[] table;//位桶 数组  存储map集合元素  null
  int threshold;//12  扩容的临界点
  TREEIFY_THRESHOLD= 8 //链表结构转换成红黑树数据结构数值判断   8
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;//第一次初始化table
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);//存储第一个元素
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;// hash冲突 key值一样 新的value替换旧value
            //如果仅仅hash一致  key值不等 比如 Ma  NB  会执行下面2个if
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            //如果节点为TreeNode  按照红黑树规则进行插入
            else {
                //按照链表执行操作
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        //将新的元素放到上一个元素next属性为null的位置
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        // TREEIFY_THRESHOLD 链表转换红黑树的临界点  7 
                        //可以避免在极端情况下  链表死循环的问题
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
                //key值一样 key的hash一致  替换旧value
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

 public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }

2.1 LinkedHashMap<k,V>

插入元素的顺序与遍历的顺序完全一致。

2.2 TreeMap<k,V>

key: 有序 会按照自然顺序进行排列。 提供排序规则。 与比较器有关系: Comparable Comparator

要求key的数据类型必须实现Comparable

   public TreeMap() {
        comparator = null;
    }
public V put(K key, V value) {
        Entry<K,V> t = root;// root = null  始终代表第一个元素
        if (t == null) {
            compare(key, key); // type (and possibly null) check

            root = new Entry<>(key, value, null);// 第一次新增元素  充当root
            size = 1;
            modCount++;
            return null;
        }
        int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
        Comparator<? super K> cpr = comparator;
         //当我们自定义比较规则的时候 使用Comparator的compare进行比较
        if (cpr != null) {
            do {//执行逻辑与下面Comparable类似
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        else {
            if (key == null)
                throw new NullPointerException();
            @SuppressWarnings("unchecked")
                Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                //调用key的数据类型重写的compareTo执行比较
                if (cmp < 0)//当前元素小  获得父节点的左边分支 再循环比较
                    t = t.left;
                else if (cmp > 0)//当前元素大 获得父节点的右边分支  再循环比较
                    t = t.right;
                else
                    return t.setValue(value);//key值一样  直接新的value替换旧的value数据
            } while (t != null);
        }
        Entry<K,V> e = new Entry<>(key, value, parent);
        if (cmp < 0)
            parent.left = e;//定位  放到父节点的左边还是右边
        else
            parent.right = e;
        fixAfterInsertion(e);//修正树
        size++;
        modCount++;
        return null;
    }

2.3 HashTable<K,V>

Hashtable() 
构造一个新的,空的散列表,默认初始容量(11)和负载因子(0.75)。  
Hashtable(int initialCapacity) 
构造一个新的,空的哈希表,具有指定的初始容量和默认负载因子(0.75)。 

2.4 ConcurrentHashMap<K,V>

public class ConcurrentHashMap<K,V>
extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable
ConcurrentHashMap() 
创建一个新的,空的地图与默认的初始表大小(16)。  
ConcurrentHashMap(int initialCapacity) 
创建一个新的空的地图,其初始表格大小适应指定数量的元素,而不需要动态调整大小。 

3. 排序

对集合元素排序。

1. 对List集合元素进行排序

public class User implements Comparable<User> {
    private Integer id;
    private String name;
    private Integer age;
    
      //排序规则
    @Override
    public int compareTo(User user) {
        //按照用户年龄升序排列
        //年龄相同 按照id降序排列
        Objects.requireNonNull(user);
        int result = user.age.compareTo(this.age);
        if(result==0){
            result = user.id.compareTo(this.id);
        }
        return result;
    }
    
}
   Collections.sort(userList, (user1, user2) -> {
            int result = user1.getAge().compareTo(user2.getAge());
            if (result == 0) {
                result = user2.getId().compareTo(user1.getId());
            }
            return result;
        });

Set集合元素排序 TreeSet

如果自定义类型的对象存储到Set集合里面 一定要去重写equals 和 hashcode

为什么要重写类型equals 和 hashcode?  规则
 

Map map集合的key元素进行排序 TreeMap

如果自定义类型的对象存储到 map集合的key元素 一定要去重写equals 和 hashcode

3.1 Collections

操作集合元素的工具类   Collections 
static <T> boolean addAll(Collection<? super T> c, T... elements)  
    将指定元素数据放入集合中  List/Set
    
 static <T extends Comparable<? super T>> void sort(List<T> list) 
 static <T> void sort(List<T> list, Comparator<? super T> c)  
 T max(Collection<? extends T> coll)  获得元素最值  按照自然顺序排列
 T max(Collection<? extends T> coll, Comparator<? super T> comp)  
     
 T min(Collection<? extends T> coll) 
 T min(Collection<? extends T> coll, Comparator<? super T> comp)  
     
 static void shuffle(List<?> list)  洗牌  打乱集合元素顺序
 static <T> List<T> synchronizedList(List<T> list)  将线程不安全的集合对象转换成安全的集合对象
 static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)  
 static <T> Set<T> synchronizedSet(Set<T> s)  
 

4. Stream

//stream()  流机制  提供了很多对集合元素操作的方法  过滤 聚合 截断
//遍历list集合的时候 执行删除 并发修改的异常  属于迭代器的 fail--fast 快速失败的机制  modCount++
//再1.8- 集合操作  不支持并行化    并行  vs  并发  再同一个时间  执行多个任务
   //1.获得流
//        Stream.of(10, 100, 100, 0, 3)
//        Arrays.stream()
        Stream<Integer> stream = hashSet.parallelStream();//集合的元素都在stream里面
        //2.操作流
        Optional<Integer> optional = stream.min((num1,num2)->{
            return num1.compareTo(num2);
        });

5. 集合嵌套

//维护省市级联的数据,通过一个省份获得所有的城市的信息
  //维护省市级联的数据,通过一个省份获得所有的城市的信息   根据key获得value
//        List<Map<String,Object>>
        // 一个省份 ---> 多个城市 List  Set
        Map<String, List<City>> map = new HashMap<>(16);
        List<City> cityList = new ArrayList<>(10);
        Collections.addAll(cityList,
                new City(1, "郑州市1"),
                new City(1, "郑州市2"),
                new City(1, "郑州市3"),
                new City(1, "郑州市4"));
        map.put("he", cityList);

        cityList = new ArrayList<>(10);
//        cityList.clear();//清空
        Collections.addAll(cityList,
                new City(2, "海淀区1"),
                new City(3, "海淀区1"),
                new City(4, "海淀区1"),
                new City(5, "海淀区1"));
        map.put("bj", cityList);

        //获得河南省份下的所有的城市
        List<City> cityList1 = map.get("he");
        System.out.println(cityList1);

List Set
Map<String, List> map = new HashMap<>(16);
List cityList = new ArrayList<>(10);
Collections.addAll(cityList,
new City(1, “郑州市1”),
new City(1, “郑州市2”),
new City(1, “郑州市3”),
new City(1, “郑州市4”));
map.put(“he”, cityList);

    cityList = new ArrayList<>(10);

// cityList.clear();//清空
Collections.addAll(cityList,
new City(2, “海淀区1”),
new City(3, “海淀区1”),
new City(4, “海淀区1”),
new City(5, “海淀区1”));
map.put(“bj”, cityList);

    //获得河南省份下的所有的城市
    List<City> cityList1 = map.get("he");
    System.out.println(cityList1);







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值