Java集合框架知识总结

一.List接口

1.特点
  1. 有序
  2. 有索引
  3. 可重复,元素可为null
  4. 底层用数组实现
2. ArrayList
2.1 实现
public class MyArrayList {
    
    /**
     * 定义数组,保存数据
     */
    private Object[] objects = null;
    /**
     * 默认数组长度
     */
    private final int DEFAULT_LENGTH = 10;
    /**
     * 数组长度
     */
    private int length;
    /**
     * 数组元素个数
     */
    private int size= 0;
    /**
     * 默认构造函数,创建数组
     */
    private final int LOAD = 2;
    public MyArray() {
        length = DEFAULT_LENGTH;
        objects = new Object[length];
    }
    /**
     * 构造函数,根据用户传入长度创建数组
     * @param length
     */
    public MyArray(int length) {
        this.length = length;
        objects = new Object[length];
    }
    /**
     * 向数组中添加元素
     * @param o
     */
    public void add(Object o) {
        //判断是否需要扩容
        if(size==length) {
            //元素个数等于了数组长度,需要扩容
            length = length*LOAD;
            objects = Arrays.copyOf(objects,length);
        }
        objects[size]=o;
        size++;
    }
    
    public void add(int index,Object o) {
        if(index<0||index>size-1) {
            throw new ArrayIndexOutOfBoundsException("访问越界");
        }else {
            //判断是否需要扩容
            if(size==length) {
                //元素个数等于了数组长度,需要扩容
                length = length*LOAD;
                objects = Arrays.copyOf(objects,length );
            }
            //先将index位置处的元素已近后面元素向右移动
            System.arraycopy(objects, index, objects, index+1, size-index);
            objects[index] = o;
            size++;
        }
        
        
    }
    
    /**
     * 数组移除操作
     * @param index
     */
    public void remove(int index) {
        if(index<0||index>size-1) {
            throw new ArrayIndexOutOfBoundsException("访问越界");
        }else {
            objects[index]= null;
            System.arraycopy(objects, index+1, objects,index , size-index);
            size--;
        }
    }
    /**
     *  查找元素所在的位置
     * @param o
     * @return
     */
    public int indexOf(Object o) {
//      if(size==0) {
//          return size;
//      }else if(size==length) {
//          return -1;
//      }else if(size=0?true:false;
    }
    /**
     * 移除所有元素
     */
    public void removeAll() {
        Arrays.fill(objects, null);
        size =0;
    }
    /**
     * 更新数组元素
     * @param index
     * @param o
     */
    public void update(int index,Object o) {
        if(index<0||index>size-1) {
            throw new ArrayIndexOutOfBoundsException("访问越界");
        }
        objects[index] = o;
    }
    /**
     * 查找某个索引处的元素
     * @param index
     */
    public Object get(int index) {
        if(index<0||index>size-1) {
            throw new ArrayIndexOutOfBoundsException("访问越界");
        }
        return objects[index];
    }
    /**
     * 打印数组元素
     */
    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer("[");
        for (int i = 0; i < size; i++) {
            sb.append(objects[i]);
            sb.append(",");
        }
        sb.append("]");
        return sb.toString().replace(",]", "]");
    }
    /**
     * 获取元素个数
     * @return
     */
    public int size() {
        return size;
    }
}
2.2 方法
方法 描述
add(Object o) 添加数据
add(int index,Object o) 在制定索引处添加元素
size() 获取元素个数
get(int index) 获取索引处的元素
isEmpty() 判断集合是否为空
indexOf(Object o) 判断某个元素第一次出现的位置
E remove(int index) 移除索引处元素,并返回该元素
boolean remove(Object o) 移除元素
clear() 清空元素
set(int index ,E e) 修改索引处的元素
iterator() 获取迭代器
trimToSize() 减少容量指当前元素个数
contains(Object o) 判断是否包含某个元素
lastIndexOf(Object o) 判断某个元素最后一次出现的位置
toArray() 将集合转换为数组
addAll(Collection c) 集合中添加集合
addAll(int index, Collection c) 索引处添加集合
retainAll(Collection c) 求两个集合的交集
removeAll(Collection c) 移除传入集合内的元素
subList(int fromIndex, int toIndex) 获取子集合
2.3List遍历
public static void main(String[] args) {
        //菱形语法
        ArrayList list = new ArrayList<>();
        list.add(1);
        list.add(4);
        list.add(2);
        for (Integer integer : list) {
            System.out.println(integer);
        }
        //使用迭代器遍历
        Iterator it = list.iterator();
        //判断是否有下一个元素
        while (it.hasNext()) {
            int i = it.next();
            System.out.println(i);
        }
}
3.LinkedList
3.1双向链表实现
public class MyLinkedList{
    /**
     * 链表元素个数
     */
    private int size;
    /**
     * 链表首节点
     */
    private Node first;
    /**
     * 链表尾结点
     */
    private Node last;
    /**
     * 默认构造创建一个空链表
     */
    public MyLinkedList() {
        first = null;
        last = null;
        size = 0;
    }
    /**
     * 在链表末尾添加元素
     * @param e
     */
    private void linkLast(E e) {
        if(first==null||last==null||size==0) {
            //说明链表为空链表
            //1.创建新节点
            //2.新节点指为first
            //3.新节点指为last
            Node newNode = new Node(null,e,null);
            first = newNode;
            last = newNode;
        }else {
            
            //1.创建新节点
            Node newNode = new Node(last,e,null);
            //2.将last节点指向新节点
            last.next = newNode;
            //3.将新节点改为last
            last = newNode;
        }
        size++;
    }
    
    /**
     * 在链表首部添加节点
     * @param e
     */
    private void linkFirst(E e) {
        if(first==null) {
            //1.创建新节点
            Node newNode = new Node(null, e, null);
            first = newNode;
            last = newNode;
        }else {
            Node newNode = new Node(null, e, first);
            first.pre = newNode;
            first = newNode;
            
        }
        size++;
    }
    /**
     * 在节点之前添加节点
     * @param index
     * @param e
     */
    private void linkBefore(int index,E e) {
        chcekRange(index);
        //1.创建新节点
        Node node = new Node(null,e,null);
        //2.找到索引处的节点
        Node indexNode = getNodeByIndex(index);
        //3.找到索引处的前置节点
        Node pre = indexNode.pre;
        //4.新节点指向前置节点
        node.pre = pre;
        //5.前置节点指向新节点
        pre.next = node;
        //6.新节点指向索引处节点
        node.next = indexNode;
        //7.索引处pre指向新节点
        indexNode.pre=node;
        size++;
    }
    /**
     * 在某个节点后插入新节点
     * @param index
     * @param e
     */
    private void linkAfter(int index,E e) {
        chcekRange(index);
        //1.获取当前索引处的节点
        Node indexNode = getNodeByIndex(index);
        //2.获取索引处后置节点
        Node next = indexNode.next; 
        //3.创建新节点
        Node newNode = new Node(indexNode,e,next);
        //4.索引处节点指向新节点
        indexNode.next = newNode;
        //5.索引处节点的后置节点指向新节点
        next.pre = newNode;
        size++;
    }
    
    /**
     * 链表中添加节点,默认添加在尾部
     * @param e
     */
    public void add(E e) {
        linkLast(e);
    }
    /**
     * 在指定索引处后面添加节点
     * @param index
     * @param e
     */
    public void add(int index,E e) {
        linkAfter(index, e);
    }
    /**
     * 删除索引处节点
     * @param index
     * @return
     */
    public boolean remove(int index) {
        chcekRange(index);
        if(index==0) {
            Node removeNode = first;
            first = first.next;
            first.pre = null;
            removeNode.next=null;
        }else if(index==size-1) {
            Node removeNode = last;
            last = last.pre;
            last.next = null;
            removeNode.pre = null;
        }else {
            //1.找到索引处的节点
            Node indexNode = getNodeByIndex(index);
            //2.找到索引处的后置
            Node next = indexNode.next;
            //3.找到索引处的前置节点
            Node pre = indexNode.pre;
            //4.将索引处前置节点的next指向索引处后置节点
            pre.next = next;
            //5.将索引处后置节点的pre指向索引处前置节点
            next.pre = pre;
            //6.减少元素个数
        }
        size--;
        return true;
    }
    
    /**
     * 根据索引获取元素
     * @param index
     * @return
     */
    public E get(int index) {
        chcekRange(index);
        Node node = getNodeByIndex(index);
        return node.data;
    }
    /**
     * 修改索引处的值
     * @param index
     * @param e
     */
    public void set(int index,E e) {
        chcekRange(index);
        Node current  = first;
        
        for (int i = 0; i < size&¤t!=null;i++,current = current.next) {
            if(i==index) {
                current.data = e;
            }
        }
    }
    /**
     * 清空链表
     */
    public void clear() {
        first =null;
        last =null;
        size=0;
    }
    /**
     * 链表是否为空
     * @return
     */
    public boolean isEmpty() {
        return size==0;
    }
    
    /**
     * 根据传入的索引找到节点
     * @param i
     * @return
     */
    private Node getNodeByIndex(int index){
        //判断索引越界
        if(index<0||index>size) {
            throw new IndexOutOfBoundsException("访问越界");
        }
        if(index==0) {
            return first;
        }else if(index==size-1) {
            return last;
        }else {
            Node current = first;
            for (int i = 0; i < size&¤t!=null; i++) {
                if(i==index) {
                    return current;
                }
                current = current.next;
            }
            
        }
        return first;
    }
    /**
     * 判断访问是否越界
     * @param index
     */
    public void chcekRange(int index) {
        if(index<0||index>size-1) {
            throw new IndexOutOfBoundsException("访问越界");
        }
    }
    /**
     * 打印链接
     */
    @Override
    public String toString() {
        if(size==0) {
            return "[]";
        }
        Node current = first;
        StringBuffer sb =new StringBuffer("[");
        for (int i = 0; i < size&¤t!=null; i++,current=current.next) {
            sb.append(current.data);
            if(i!=size-1) {
                sb.append(",");
            }
        }
        sb.append("]");
        return sb.toString();
        
    }
    
    /**
     *  定义非静态内部类表示节点
     * @author MR.W
     *
     * @param 
     */
    class Node{
        Node pre;
        E data;
        Node next;
        public Node(Node pre, E data, Node next) {
            super();
            this.pre = pre;
            this.data = data;
            this.next = next;
        }
    }
    
}

3.2 方法
方法 描述
add(Object o) 添加数据
add(int index,Object o) 在指定索引处添加元素
size() 获取元素个数
get(int index) 获取索引处的元素
isEmpty() 判断集合是否为空
indexOf(Object o) 判断某个元素第一次出现的位置
E remove(int index) 移除索引处元素,并返回该元素
boolean remove(Object o) 移除元素
clear() 清空元素
set(int index ,E e) 修改索引处的元素
addFirst(E e) 链表首部添加元素
addLast(E e) 链表末尾添加元素
removeFirst() 移除首节点
removeLast() 移除尾节点
getFirst() 获取第一个节点
getLast() 获取最后一个几点

二.Set接口

1.特点
  1. 无序
  2. 无索引
  3. 不可重复
2.HashSet
2.1方法
方法 描述
add(Object o) 添加元素
remove(Object o) 移除元素
isEmpty() 判断元素是否为空
2.2.HashSet遍历
public class Test {
    public static void main(String[] args) {    
        Set set = new HashSet<>();
        //添加元素
        set.add("陈忠实");
        set.add("贾平凹");
        set.add("路遥");
        set.add("张爱玲");
        set.add("林徽因");
        boolean a = set.add("徐志摩");
        System.out.println(a);
        boolean b = set.add("徐志摩");
        System.out.println(b);
        //foreach
        for (String s : set) {
            System.out.println(s);
        }
        //iterator
        Iterator it = set.iterator();
        while (it.hasNext()) {
            String s = it.next();
            System.out.println(s);
        }
    }
}
2.3重写hashCode规则
  1. 同一对象多次调用hashCode()方法时,返回值应该相同
  2. equals()方法返回值为true时,hashCode应该相同
  3. 所有参与equals方法的成员变量,都应该参与hashCode计算(为防止偶然和相等,造成hash冲突,应该用每个成员变量乘以一个质数)
3.TreeSet

三.Map接口

1.HashMap
1.1方法
方法 描述
put(K key,V value) 添加键值对
get(Object key) 根据键获取值
keySet() 获取keySet
entrySet() 获取entrySet
containsKey(Object key) 判断是否存在key
remove(Object key) 根据key删除键值对
remover(Object key,Object value) 根据key和value删除键值对
size() 获取元素个数
isEmpty() 判断map是否为空
1.2HashMap遍历
//利用keySet()方法获取keySet
public static void main(String[] args) {
    Map map = new HashMap();
    map.put("乔峰",30);
    map.put("虚竹", 20);
    map.put("李秋水", 20);
    map.put("天山童姥", 60);
    map.put("梦姑",18);
    //先获取keySet
    Set set = map.keySet();
    //获取迭代器
    Iterator it = set.iterator();
    //利用迭代器遍历
    while (it.hasNext()) {
        String key = it.next();
        int i = map.get(key);
        System.out.println("key==========="+key);
        System.out.println("value========="+i);
    }
}
//利用entrySet()获取entrySet
public static void main(String[] args) {
    Map map = new HashMap();
    map.put("乔峰",30);
    map.put("虚竹", 20);
    map.put("李秋水", 20);
    map.put("天山童姥", 60);
    map.put("梦姑",18);
    //获取键值对集合
    Set> set = map.entrySet();
    //遍历set
    for (Entry entry : set) {
        String key = entry.getKey();
        Integer value = entry.getValue();
        System.out.println("key=========="+key);
        System.out.pintln("key=========="+value);
    }
}
1.3HashMap和Hashtable的 区别
  1. HashMap和Hashtable都是Map接口的子类

  2. HashMap的key和value都可以为null,只能存入一个为null的key,Hashtable的key和value都不能为null

  3. HashMap非线程安全,Hashtable线程安全

2.TreeMap

四.面试题

  1. ArrayList,Vector,LinkedList的区别
    1. ArrayList,Vector底层实现是数组,LinkedList底层实现是双向链表
    2. Vector线程安全,ArrayList,LinkedList非线程安全
    3. ArrayList,Vector查找快,增删慢,LinkedList增删快,查找慢
    4. ArrayList,Vector,LinkedList都是List接口的实现类
    5. ArrayList,Vector,LinkedList都有序,有索引,可重复。

你可能感兴趣的:(Java集合框架知识总结)