【Java集合类】- Java集合类

Java集合类

一、Collection集合

概念:对象的容器,实现了对 对象的操作,类似数组功能

集合与数组的区别:数组长度固定,集合长度不固定

​ 数组可以存基本数据类型和引用类型,而集合只能存引用类型

Collection体系

1.1 Collection类的基本方法

案例:Collection的基本方法以及操作

public class test01Collection {
    public static void main(String[] args) {
        //1.创建一个集合,用的ArrayList 是有序的
        Collection collection = new ArrayList();
        //2.添加元素
        collection.add("苹果");
        collection.add("西瓜");
        collection.add("猕猴桃");
        System.out.println("元素个数:"+collection.size());
        System.out.println(collection);
        //3.删除其中一个
        collection.remove("苹果");
        //4.删除所有
//        collection.clear();
        //5.遍历集合for each
        for (Object item:collection) {
            System.out.println(item);
        }
        //6.使用迭代器遍历
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()){
            String s = (String) iterator.next();
            System.out.println(s);
        }
        //7.判断
        System.out.println(collection.contains("苹果"));
        System.out.println(collection.isEmpty());
    }
}

1.2 List类的基本方法

案例:list的基本方法以及操作

public class test02_List {
    public static void main(String[] args) {
        //1.list的创建
        List list = new ArrayList();
        list.add("MMing");
        list.add("Aifleft");
        list.add("LongSkr");
        list.add("Forever");
        list.add(4,"lionkk");
        System.out.println(list.toString());

        //2.删除
        list.remove(4);
        System.out.println(list.toString());

        //3.遍历 fori foreach Iterator ListIterator

        //for i
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

        //for each
        for (Object item: list) {
            System.out.println(item);
        }

        // Iterator
        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }

        // ListIterator 相对于普通的 Iterator 可以进行前驱和后继的寻找
        ListIterator listIterator = list.listIterator();
        while (listIterator.hasNext()){
            System.out.println(listIterator.next());
        }

        while (listIterator.hasPrevious()){
            System.out.println(listIterator.previous());
        }

        //4.sublist 进行区间截取
        List sublist = list.subList(0,2);
        System.out.println(sublist.toString());
    }
}

1.3 List实现类

1)ArrayList:实现是 数组,查询快,增删慢,运行效率快,但线程不安全

2)LinkedList:实现是 链表,查询慢,增删快

3)Vector: 实现是 数组,查询慢,增删快,运行效率慢,但线程安全

1.3.1 ArrayList

案例:ArrayList的基本方法操作

public class test02_ArrayList {
    public static void main(String[] args) {
        //1.添加数据到list
        ArrayList arrayList = new ArrayList();
        Student s1 = new Student("裴珠泫",20);
        Student s2 = new Student("金珍妮",20);
        Student s3 = new Student("柳智敏",20);
        Student s4 = new Student("宁艺卓",20);
        Student s5 = new Student("李秀满",50);
        arrayList.add(s1);
        arrayList.add(s2);
        arrayList.add(s3);
        arrayList.add(s4);
        arrayList.add(s5);
        System.out.println(arrayList.toString());

        //2.删除元素
//        arrayList.remove(s5);
//        System.out.println(arrayList.toString());

        //3.删除元素(通过new 方法) 需要重写对应类的equals方法 涉及remove的源码
        arrayList.remove(new Student("李秀满",50));
        System.out.println(arrayList.toString());

        //4.遍历 fori foreach Iterator ListIterator
        for (int i = 0; i < arrayList.size(); i++) {
            System.out.println(arrayList.get(i));
        }

        for (Object o:arrayList) {
            System.out.println(o);
        }

        Iterator iterator = arrayList.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

        ListIterator listIterator = arrayList.listIterator();
        while (listIterator.hasNext()){
            System.out.println(listIterator.next());
        }

        while ((listIterator.hasPrevious())){
            System.out.println(listIterator.previous());
        }

        //5.判断
        boolean result = arrayList.contains(new Student("裴珠泫",20));
        System.out.println(result);

        //6.查找
        System.out.println(arrayList.indexOf(new Student("金珍妮",20)));
    }
}

案例:ArrayList源码分析

/**
 * Default initial capacity.
 */
private static final int DEFAULT_CAPACITY = 10;

默认容量:10

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

ArrayList的add方法:里面调用了 ensureCapacityInternal方法,传递了一个size+1(新的ArrayList就是1)的参数

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

ensureCapacityInternal方法:保证内部的容量方法(一个缓存方法),接收了size+1(新的ArrayList就是1)参数,继续调用ensureExplicitCapacity方法,参数为calculateCapacity方法

返回的int值

private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}

calculateCapacity方法:用于得出真实容量的方法,需要两个参数,当前元素数据和minCapacity(size+1)的容量

方法内部进行判断,是否为空数组,如果是,返回默认容量(10)和minCapacity (size+1如果是新的ArrayList就是1)之间大的数字

如果不是空数组就返回

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

ensureExplicitCapacity方法:保证明确容量方法,参数就是calculateCapacity的返回值,里面进行了一个判断,

如果minCapacity(与DEFAULT_CAPACITY比较完会变成10)- 当前对象的长度 大于 0,就执行grow增长方法传递minCapacity参数

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    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);
}

进行了一些列的比较与赋值,最后执行了Array.copyOf()方法 复制拷贝生成了新的 list对象,把对象添加了进去

1.3.2 Vector

案例:vector的常用方法(添加 删除与list都类似 下面仅写出特有的枚举器遍历

public class test02_Vector {
    public static void main(String[] args) {
        Vector vector = new Vector();
        vector.add("ONE");
        vector.add("TWO");
        vector.add("THREE");

        //重点写一下vector的 枚举器遍历
        Enumeration e = vector.elements();
        while (e.hasMoreElements()){
            System.out.println(e.nextElement());
        }
    }
}
1.3.3 LinkedList

用法与ArrayList基本一致,实现是用双向链表

案例:LinkedList源码

transient int size = 0;

/**
 * Pointer to first node.
 * Invariant: (first == null && last == null) ||
 *            (first.prev == null && first.item != null)
 */
transient Node<E> first;

/**
 * Pointer to last node.
 * Invariant: (first == null && last == null) ||
 *            (last.next == null && last.item != null)
 */
transient Node<E> last;

默认的容量为0, 一个头节点,一个尾节点

public boolean add(E e) {
    linkLast(e);
    return true;
}

add方法里面 调用了linklast方法

/**
 * Links e as last element.
 */
void linkLast(E e) {
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}

当添加一个元素到空链表

1.3.4 ArrayList 和 LinkedList区别

1.4 泛型

概念:泛型就是参数化类型,把类型作为参数传递

优点:提高代码的重用性,防止类型转换异常,提高代码的安全性

1.5 Set类

特点:无序,无下标,元素不重复

方法:全部继承于Collection中的方法

使用:基本方法于list类似,不可用fori 进行遍历

1.5.1 HashSet

存储结构:哈希表(数组+链表(+红黑树))

存储过程:1)根据对象的hashcode计算在数组中的保存位置,如果当前位置为空,直接保存,不为空执行下一步

​ 2)不为空,执行equals方法,如果equals方法为true,会判断重复放弃保存,为false会形成链表

案例:HashSet基本使用,以及 通过重写Student的hashcode 和 equals方法 来判断元素一致性

public class test03_HashSet {
    public static void main(String[] args) {
        //1.新建一个HashSet 存入数据
        HashSet<Student> hashSet = new HashSet<Student>();
        Student s1 = new Student("西八哥",22);
        Student s2 = new Student("王德发",32);
        Student s3 = new Student("Lolita",18);
        hashSet.add(s1);
        hashSet.add(s2);
        hashSet.add(s3);
        //2.打印目前数据,是无序的
        System.out.println(hashSet.toString());
        //3.通过重写hashcode和equals方法 来进行判定是否为一个数据对象
        Student s4 = new Student("王德发",32);
        hashSet.add(s4);

        System.out.println(hashSet.toString());
        //4.遍历 fori foreach 迭代器
        //5.判断
    }
}

重写的两个方法

@Override
public int hashCode() {
    //1.获取到name的hashcode,内部已包装好 就是通过name去判断的
    int n1 = this.name.hashCode();
    //2.获取到age,简便就不获取hashcode的值了,已经可以进行唯一判断了
    int n2 = this.age;

    return n1+n2;
}

@Override
public boolean equals(Object obj) {
    //1.判断是不是为同一个对象
    if(this==obj){
        return true;
    }
    //2.判断是否为空
    if(obj==null){
        return false;
    }
    //3.判断是否为Student类
    if(obj instanceof Student){
        Student s = (Student) obj;
        //4.进行所需比较
        if(this.getName()==s.getName() && this.getAge()==s.getAge()){
            return true;
        }
    }
    //5.都不满足
    return false;
}

HashSet源码 其实HashSet里面用的就是一个HashMap

private transient HashMap<E,Object> map;

    public HashSet() {
        map = new HashMap<>();
    }

    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
1.5.2 TreeSet

存储结构:红黑树

特点:1)基于排列顺序实现元素不重复

​ 2)实现了SortedSet接口,对元素进行了排序

​ 3)元素对象必须实现Compareable接口,指定排序规则

​ 4)通过Compareto方法确定是否为重复元素

案例:进行添加重复元素,观察TreeSet结果

public class test03_TreeSet {
    public static void main(String[] args) {
        TreeSet<Student> treeSet = new TreeSet<Student>();
        Student s1 = new Student("西八哥",22);
        Student s2 = new Student("王德发",32);
        Student s3 = new Student("Lolita",18);
        Student s4 = new Student("Lolita",18);
        treeSet.add(s1);
        treeSet.add(s2);
        treeSet.add(s3);
        treeSet.add(s4);
        System.out.println(treeSet.toString());
    }
}

注意:通过TreeSet存储引用类型,必须要实现Comparable的CompareTo方法

Student类中重写的CompareTo方法 (进行数据排序)

@Override
public int compareTo(Student o) {
    int n1 = this.getName().compareTo(o.getName());
    int n2 = this.getAge()-o.getAge();
    return n1==0?n2:n1;
}

对于实现Comparable接口的另一种实现方法,在创建TreeSet的时候,使用Compartor 匿名内部类直接重写CompareTo方法

TreeSet<Student> treeSet = new TreeSet<Student>(new Comparator<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
        int n1 = o1.getName().compareTo(o2.getName());
        int n2 = o1.getAge()-o2.getAge();
        return n1==0?n2:n1;
    }
});

案例:通过TreeSet判定字符串的大小

public class test03_TreeSetDemo {
    public static void main(String[] args) {
        TreeSet<String> treeSet = new TreeSet<String>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                int n1 = o1.length()-o2.length();
                int n2 = o1.compareTo(o2);
                return n1==0?n2:n1;
            }
        });
        treeSet.add("helloworld");
        treeSet.add("pingguo");
        treeSet.add("lisi");
        treeSet.add("zhangsan");
        treeSet.add("beijing");
        treeSet.add("cat");
        System.out.println(treeSet.toString());
    }
}

二、Map集合类

特点:1)存储任意键值对,key-value

​ 2)键 :无序、无下标、不可重复

​ 3)值:无序、无下标、可重复

​ 4)如果存入相同的key,且识别为同一个对象,那对应的value会被新的value覆盖

案例:使用Map 进行数据增加 删除 和 遍历

public class test04_Map {
    public static void main(String[] args) {
        //1.Create a new map
        Map<String,String> map = new HashMap<String,String>();
        //2.Add data to map
        map.put("one","XBOX");
        map.put("two","PS5");
        map.put("three","SWITCH");
        map.put("four","SWITCH");
        System.out.println(map.toString());
        //3.Delete data
        map.remove("two");
        System.out.println(map.toString());
        //ps: If the same key,the value will be covered
        map.put("four","SWITCHHHHHHHHHHHH");
        //4.Print map - two way - keySet - EntrySet
        //keySet
        System.out.println("--------------By Key Set-----------------");
        Set<String> keySet = map.keySet();
        for (String key:keySet) {
            System.out.println(key+"--->"+map.get(key));
        }
        //EntrySet
        System.out.println("--------------By EntrySet-----------------");
        for (Map.Entry<String,String> set:map.entrySet()) {
            System.out.println(set.getKey()+"---->"+set.getValue());
        }
    }
}

2.1 HashMap

特点:线程不安全,运行效率快,允许使用null作为key、或者value

案例:使用Student类作为key , String类型作为value进行HashMap的操作

public class test04_HashMap {
    public static void main(String[] args) {
        //1.Create a new HashMap, key is Student - value is String
        HashMap<Student,String> hashMap = new HashMap<>();
        hashMap.put(new Student("一花",20),"老大");
        hashMap.put(new Student("二乃",20),"老二");
        hashMap.put(new Student("三玖",20),"老三");

        System.out.println(hashMap.toString());
        //2.override hashcode and equals method to distinct the data
        hashMap.put(new Student("三玖",20),"忙内");
        System.out.println(hashMap.toString());

        //3. Delete、Print、ergodic、the same with Map
    }
}

注意:如果想要程序把新的Student对象 识别为已有,需要重写Student类的hashcodeequals方法

案例:Has和Map源码分析

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16   ---默认初始化大小
static final int MAXIMUM_CAPACITY = 1 << 30;					----最大的容量
static final float DEFAULT_LOAD_FACTOR = 0.75f;					 ---默认加载因子,到总大小的75%进行扩容
static final int TREEIFY_THRESHOLD = 8;						 ---当链表长度大于8,转换为红黑树
static final int UNTREEIFY_THRESHOLD = 6;					 ---当链表长度小于6  转化为链表
static final int MIN_TREEIFY_CAPACITY = 64;					 ---数组长度大于链表长度大于8,集合元素大于64转换红黑树
transient Node<K,V>[] table;								 ---哈希表中的 数组
transient int size;											 ---元素个数

put方法源码

//1.调用putVal方法-->传对应值进去
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

//2.进行数组resize,resize完毕后,把当前节点放入对应位置
    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;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
//3.resize完后,返回resize完后大小的数组
    final Node<K,V>[] resize() {
        Node<K,V>[] oldTab = table;
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
        int oldThr = threshold;
        int newCap, newThr = 0;
        //中间代码省略
        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
        table = newTab;
//4.resize的扩容,当到达装载因子的边界,会进行扩容,是原来的两倍
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
           oldCap >= DEFAULT_INITIAL_CAPACITY)
             newThr = oldThr << 1; // double threshold

过程解析:

1)HashMap刚创建时,table是null,为了节省空间,当添加第一个元素时,table容量调整为16

2)当元素个数大于(16*0.75=12时),会进行扩容,扩容后会变为原来的2倍

3)JDK1.8之前是头插法,1.8之后是尾插法

2.2 TreeMap

特点:实现了SortedMap接口,可以对key自动排序,泛型对象要实现Comparable接口 同TreeSet

三、Collections工具类

案例:Collections工具类的方法使用

public class test05_Collections {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(10);
        list.add(156);
        list.add(121);
        list.add(1);

        //sort
        System.out.println(list.toString());
        Collections.sort(list);
        System.out.println(list.toString());

        //binarySearch return index
        System.out.println(Collections.binarySearch(list,156));

        //copy ps:the length must same
        List<Integer> list2 = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            list2.add(0);
        }
        Collections.copy(list2,list);
        System.out.println(list2.toString());

        //reverse
        Collections.reverse(list);
        System.out.println(list.toString());

        //shuffle break the order
        Collections.shuffle(list);
        System.out.println(list.toString());

        //list convert to array
        Integer[] array = list.toArray(new Integer[10]);
        System.out.println(Arrays.toString(array));

        //array convert to list
        String[] names = {"A","B","C"};
        List<String> list3 = Arrays.asList(names);
        System.out.println(list3.toString());

        //ps: as int、byte type data need to use Integer、Byte
        Integer[] nums = {3,2,45};
        List<Integer> list4 = Arrays.asList(nums);
        System.out.println(list4.toString());
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值