java集合详解


集合的分类

  • Collection集合(单列集合的接口)

       List接口集合(存取有序,集合可有重复值,有索引的)
       	实现类
              ArrayList (底部通过数组)
              LinkedList(底部通过双向链表实现)
              Vector(线程安全 也是数组实现)--->Stack(线程安全的栈)
     
       set接口集合(存取无序,不可有重复值,无索引)
       	 实现类
       	       Hashset(底部通过哈希表)--->LinkedHashset(底部哈希表+链表)
       	     (无序,不可有重复值,无索引)(有序,不重复,无索引)						
          	   TreeSet(底部通过红黑树) (默认按升序排列,不可有重复值,无索引)
    
  • Map集合(双列集合的接口 键值对的数据)

       	 实现类
       	     HashMap(哈希表)
       	     LinkedHashMap(哈希表+链表)
       	     TreeMap(红黑树)
    
  • Iterator迭代器

        一般iterator
         其他迭代器
    

集合的整体框架图
在这里插入图片描述

  • 集合只能存储引用类型

一、Iterator接口(迭代器)

  • 提供的方法
    在这里插入图片描述
  • Iterable 含有foreach.迭代器和一个分离器

 - Iterator<T> iterator();  //迭代器
 - void forEach(Consumer<? super T> action) //增强for循环
 - void Spliterator<T> spliterator() //分离器

迭代器需要注意的地方

   
         * 当使用迭代器遍历的时候一定要注意:
         * 1.只要调用过一次next(),指针就会下移
         * 2.当出现迭代器和集合并行调用时会出现并行异常
         *   throw ConcurrentModificationException //并行修改异常
         *    while (iterator.hasNext()){
         *    strings.remove(iterator.next());
         *    有一种特殊情况会不报错
         *    当前检查异常的方法 当modCount == expectedModCount时
         * 就不会报错一般在倒数几个,和你使用next()次数有关
         *    final void checkForComodification() {
         *        if (modCount != expectedModCount)
         *         throw new ConcurrentModificationException();
         *        }
         * 3.在想要删除元素时,可以通过迭代器自己的  iterator.remove();
         * 4.想要使用add(),需要使用下层迭代器ListIterator

当需要在迭代器中进行插入操作的时候上层迭代器时没有add方法的,可以使用下层接口的迭代器

  ListIterator<String> stringListIterator = list.listIterator();
        while (stringListIterator.hasNext()){
            stringListIterator.add("dsadfasf");

二、Collection接口

  • 提供的方法
    基本都是一些增删改查和流的方法
        int size (); //大小
        boolean isEmpty (); //判空
        boolean contains (Object o); //包含
        <T> T[]toArray(T[]a);//转数组
        boolean add (E e);  //添加
        boolean remove (Object o); //删除
        boolean containsAll (Collection < ? > c); //包含
        boolean addAll (Collection < ? extends E > c); //添加
        boolean removeAll (Collection < ? > c);
        void clear (); //清除
        default
        Stream<E> stream () //顺序流
        Stream<E> parallelStream () //并行流
  
  

遍历方式(五种)

       //迭代器
       Iterator<String> iterator = strings.iterator();
        while (iterator.hasNext()){

            System.out.println(iterator.next());
        }
        //增强for(也是迭代器实现)
        for (String str : strings){
            System.out.println(str);
        }
        //foreach(都行)
        strings.forEach(System.out::println);
        strings.forEach((String s)->{
            System.out.println(s);
        });
        strings.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
         //fori(需要逻辑判断,因为数组删除,增加会自动向前或者向后一定一位,可能会造成误差,少读)
        
        // 集合stream流(流不修改数据,只操作数据)
        strings.stream().forEach(System.out::println);
       

List集合

  • 通过接口List中的静态方法of()获取一个定长的集合 ,set.map接口都可以使用of()静态方法创建一个定长的数组
    通过把他调用集合的构造方法实现批量输入(当放入调用集合,它就不会影响新集合是否定长)
ArrayList<String> strings1 = new ArrayList<>(List.of("a", "b", "c", "d"));
//批量输入还可以使用其他,比如Collections工具类
boolean b = Collections.addAll(new ArrayList<>(), "b", "c", "a"); //注意这里是一个boolean值
//当然还可以使用集合的addall()这类型的方式实现批量增加
//当然也可以使用Steam流的方式,对集合进行批量的添加

 - List<String> a = List.of("a", "b", "c", "d");
 - //这里用到了一个不定传入参数的方法
 -  static int getSum(int... a){  //a本质上是一个数组  //如果这个方法存在可变参数,一定要放在最后
        int sum=0;
        for (int i : a) {
            sum+=i;
        }
        return sum;
    }
 - 
  • 提供的特有方法
    基本都是和索引相关的方法
boolean addAll(int index, Collection<? extends E> c); //提供从位置插入所有
void replaceAll(UnaryOperator<E> operator) //替代所有
void sort(Comparator<? super E> c) //通过comparator进行排序
E get(int index) //根据下标获取元素
E set(int index, E element) //根据下标设置元素
void add(int index, E element); //根据下标增加元素
E remove(int index) //删除元素
int indexOf(Object o); //返回第一次出现数组下标
 int lastIndexOf(Object o) //返回最后依次出现的下标
List<E> subList(int fromIndex, int toIndex);//返回之间的左包右不包
static <E> List<E> copyOf(Collection<? extends E> coll) //备份

ArrayList类

  • 默认容量
    当创建集合时是为一个空的数组;
    向空数组加元素时
  //  通过add()-->grow()
  return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity
   DEFAULT_CAPACITY = 10
  • 当存入超过10时 自增策略
 private Object[] grow(int minCapacity) {
        int oldCapacity = elementData.length;
        //当数组不为空还超出数组长度时
        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) 
{
            int newCapacity = ArraysSupport.newLength(oldCapacity,
                    minCapacity - oldCapacity, /* minimum growth */
                    oldCapacity >> 1  //除二操作          /* preferred growth */);
                  //数组长度的自增是通过数组的cpoyof复制到新长度下的数组中,不是在后面添加长度,所以自增时非常耗时的操作当提前预知需要的多少的时候,可以提前给数组赋长度值
            return elementData = Arrays.copyOf(elementData, newCapacity);
        } 
        }
    }
    //新长度定义策略
     public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
        // preconditions not checked because of inlining
        // assert oldLength >= 0
        // assert minGrowth > 0

        int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow
        if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {
            return prefLength;
        } else {
            // put code cold in a separate method
            return hugeLength(oldLength, minGrowth);
        }
    }
		//异常处理,健壮性
    private static int hugeLength(int oldLength, int minGrowth) {
        int minLength = oldLength + minGrowth;
        if (minLength < 0) { // overflow
            throw new OutOfMemoryError(
                "Required array length " + oldLength + " + " + minGrowth + " is too large");
        } else if (minLength <= SOFT_MAX_ARRAY_LENGTH) {
            return SOFT_MAX_ARRAY_LENGTH;
        } else {
            return minLength;
        }
    }
  • 提供的方法
void trimToSize() //修剪容量到当前容量大小

LinkedList

由于是双向链表的实现
提供的特有方法都和链表有关

 public E removeFirst() //头部删除
 public E removeLast() //尾部删除
 public void addFirst(E e)	//头插法
 public void addLast(E e) //尾插法

Vector

是线程安全的list集合
它的增删改查都是加了sychronized锁的

public synchronized void removeElementAt(int index) 
public synchronized void insertElementAt(E obj, int index) 
public synchronized void addElement(E obj)
public synchronized E get(int index)

Set接口

存取无序,无索引,不可以存取重复值
当为自定义对象的时候,通过equals()方法和hashcode()进行两个对象的比较进行去重

HashSet Hash

底部实现:哈希

哈希表时通过数组加链表的方式来实现,8之后在链表长度超过8之后就会转化为红黑树,在减少的时候链表变为6转换为链表

//计算hash值之后膜16 ,就不能预知取出的顺序了取时按数组下标进行取
static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
//HashSet创建对象时调用的是HashMap的构造方法
 public HashSet() {
        map = new HashMap<>();
    }
//默认长度为16(第一次put分配)
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
//负载因子为0.75,扩容机制  当扩容因子超过阀值的时候将数组两倍扩容
static final float DEFAULT_LOAD_FACTOR = 0.75f;
  else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)
                newThr = oldThr << 1; // double threshold
//调用的add方法也是使用了Map集合中的put
   public boolean add(E e) {
   //以key值作为存储对象,value为空
          return map.put(e, PRESENT)==null;
      }
      //当key存在的时候只会替换value,然后可以返回旧的value值
     if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }

TreeSet

底部实现:红黑树

三.Map集合

map集合的put方法有添加和修改的功能
remove方法通过key值进行删除
提供ContainsValue,ContainsKey进行查询是否存在

双列集合
Key不重复,存取无序,无索引

Map的遍历

 /*
            Map集合的三种遍历方式
            1.通过keySet
            2.通过entrySet
            3.通过foreach
         */
        Set<String> strings = hm.keySet();
        for (String string : strings) {
            System.out.println(string+" "+hm.get(string));
        }
        Set<Map.Entry<String, String>> entries = hm.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            System.out.println(entry.getKey()+" "+entry.getValue());
        }
        hm.forEach((a,b)-> System.out.println(a+" "+b));

HashMap

底层实现:哈希表
保证键唯一

LinkedHashMap

底层实现:链表+哈希表
加上了一个双链表,可以通过双链表找到下一个元素,所以变得存取有序

TreeMap

底层实现:红黑树
可以进行键内部排序

四. Compartor和Comparable

当既有Compartor又有Comparable时比较器的优先级比较高,自然排序比较低
其中第一个元素也会调用compareTo,和自己比较就算为0也会存进去
String自然排序为字典排序

//Compartor是用于集合内部排序使用作用与集合的构造方法 实现的是compare方法
  TreeSet<Student> set  = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
              int ageSort=  o1.getAge()-o2.getAge();
              //return为负值向左走,为正值向右走
             return ageSort==0?o1.getName().compareTo(o2.getName()):ageSort;
            }
        });
//Compaarable是用于自定义类,实现的是comparTo方法,进行排序
class Student implements Comparable<Student>{
    @Override
    public int compareTo(Student o) {
    //年龄主要排序,姓名次要排序
       int agesort= this.getAge()-o.getAge();
        return  agesort==0?this.getName().compareTo(o.getName()):agesort;
        
    }


五.Collections工具类

可以实现的功能

  • 使得集合不可修改
  • 使得集合支持同步
  • 交换集合中两个值的位置
  • 排序
  • 反转
  • 使其随机
  • 添加一个集合
  • 二分查找
  • 最大,最小

六.数据结构模拟实现

双向链表

节点

//节点
class DouleNode<T> {
    T val; // 节点值
    DouleNode prev; //直接前驱
    DouleNode next; //直接后驱

    public DouleNode(T val) {
        this.val = val;
    }
}

实现

public class DoubleLinkNode<T> { //双向链表

    private DouleNode head; //头部
    int size; //链表长度

    public DoubleLinkNode() { //初始化头部
        head = null;
        size = 0;
    }

    //头插法
    public void addFromFirst(T data) {
        DouleNode newNode = new DouleNode(data);
        if (this.head == null) {
            this.head = newNode;
            size++;
        } else {
            newNode.next = this.head;
            this.head.prev = newNode;
            this.head = newNode;
            size++;
        }
    }

    //尾插法
    public void addLast(T data) {
        DouleNode newNode = new DouleNode(data);
        if (this.head == null) {
            this.head = newNode;
            size++;
        } else {
            DouleNode cache = this.head;
            while (cache.next != null) {
                cache = cache.next;
            }
            cache.next = newNode;
            newNode.prev = cache;
            size++;
        }
    }

    ;

    //任意位置插入,第一个数据节点为0号下标
    public boolean addIndex(int index, T data) {
        DouleNode cache = head;
        if (size < index) {
            System.out.println("插入失败");
            return false;
        } else {
            for (int i = 0; i < index; i++) {
                cache = cache.next;
            }

            DouleNode newNode = new DouleNode(data);
            newNode.next = cache;
            ///
            newNode.prev = cache.prev;
            cache.prev = newNode;
            newNode.prev.next = newNode;
            size++;
            return true;
        }

    }

    ;

    //打印
    public void display() {
        DouleNode cache = head;
        for (int i = 0; i < size; i++) {

            System.out.println(cache.val);
            cache = cache.next;
        }
    }

    ;
   /* //查找是否包含关键字key是否在链表当中
    public boolean contains(T key){

    };
    //删除第一次出现关键字为key的节点
    public void remove(int key);
    //删除所有值为key的节点
    public void removeAllKey(int key);
    //得到双链表的长度
    public int size();
    //打印双链表
    //销毁双链表
    public void clear();*/


}

单链表

节点

class Node<T>{ //数据类型 节点
    T data;   //节点数据
    Node next;  //指向下一个节点

    public Node() {
    }

    public Node(T data, Node next) {
        this.data = data;
        this.next = next;
    }

    @Override
    public String toString() {
        return "Node{" +
                "data=" + data +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Node<?> node = (Node<?>) o;
        return Objects.equals(data, node.data) ;
    }

    @Override
    public int hashCode() {
        return Objects.hash(data, next);
    }
}

实现


public class LinkNode<T> {

        Node phead;
    public LinkNode() {  //初始化
        phead = new Node<>(null, null);
    }

    //头插法
    public void addFromHead(T data){
        Node<T> newNode = new Node<>(data, null);
        Node last= phead;
        if (last.next == null) {
            last.next=newNode;
            return;
        }
        newNode.next=last.next;
        last.next=newNode;
    }
    //尾插法
    public void addFromLast(T data){
        Node<T> newNode = new Node<>(data,null);
        Node last= phead;
        if (last.next == null) {
            last.next=newNode;
            return;
        }
        while (last.next != null) {
            last.next=last;
        }
        last.next=newNode;
    }
    //删除节点
    public void remove(T t){
        Node<T> remoNode = new Node<>(t, null);
        Node last = phead;
        if (last == null) {
            System.out.println("链表为空");
            return;
        }
        while(last.next!=null){
            if (last.next.equals(remoNode)){
                last.next=last.next.next;
                System.out.println("删除成功");
                break;
            }
            last=last.next;
        }
    }
    //循环打印
    public void printLink(){
        Node last=phead;
        if (last.next == null) {
            System.out.println("链表为空");
            return;
        }
        while (last.next != null) {
            System.out.println(last.next);
            last=last.next;
        }
    }

}

循环链表的实现

节点

 class LoopNode<T> {
    T data;
    LoopNode next;

     public LoopNode() {
     }


     public T getData() {
         return data;
     }

     public LoopNode(T data) {
         this.data = data;
     }

     public void setData(T data) {
         this.data = data;
     }

     public LoopNode getNext() {
         return next;
     }

     public void setNext(LoopNode next) {
         this.next = next;
     }
 }

实现

public class LoopLinkNode {
    private LoopNode head;
    private LoopNode last;
    int size;

    public LoopLinkNode() {
        head=last=null;
        size=0;
    }

    public void addFromHead(LoopNode newNode){
        if(size==0){
            newNode.setNext(newNode);
            head=last=newNode;
            size++;

        }else{
            last.setNext(newNode);
            newNode.setNext(head);
            head=newNode;
            size++;
        }

    }
    public void addFromLast(LoopNode newNode){
        if(size==0){
            newNode.setNext(newNode);
            head=last=newNode;
            size++;

        }else{
            last.setNext(newNode);
            newNode.setNext(head);
            last=newNode;
            size++;
        }
    }
    public void  printLoopList(){
        LoopNode cache = new LoopNode();
        cache=head;
        while(cache.next!=head){
            System.out.println(cache.getData());
            cache=cache.next;
        }
        System.out.println(cache.getData());

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值