14、java基础——Collection集合、List集合、Set集合、内部类、Map集合

集合

集合和数组是一样,都是用来存放数据

  • 数组需要手动扩容

  • 集合不需要,而且功能更加强大

1. Collection集合

Collection是一个接口,定义集合这类事物有啥方法和功能或者作用

public interface Collection<E> extends Iterable<E> { 
​
    //元素个数
    int size();
    
    //是否为空
    boolean isEmpty();
    
    //是否包含某个值
    boolean contains(Object o);
    
    //迭代器   遍历元素
    Iterator<E> iterator();
    
    //转化为数组
    Object[] toArray();
    
    <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();
    
    boolean equals(Object o);
}

2. List集合

List集合是Collection的子接口,是有序可重复的集合

  • 有序:添加的每个元素(值)都有一个下标,下标从0开始,依次递增1

  • 可重复:元素/值,是可以重复的

public interface List<E> extends Collection<E> {
    //可以通过下标获取元素的值
    E get(int index);
}
package com.qfedu;
​
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
​
public class Demo02 {
​
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();   // ctrl+shift+o
        
        //添加
        list.add(1);
        list.add(3);
        list.add(2);
        list.add(1);
        
        //获取集合的元素个数
        int size = list.size();
        
        //遍历
        for(int i=0; i<size; i++) {
            System.out.println(list.get(i));
        }
        
        //排序
        Collections.sort(list);
        
        System.out.println(list);
        
        
    }
}

2.1 ArrayList集合

ArrayList是List集合的实现类,ArrayList底层是一个数组

  • 当第一次添加元素时,ArrayList中elementData属性扩容到10

    • elementData的数据类型为Object[],就是真正存储数据的地方

  • 第2,3,4,....,10添加,数组都不会扩容

  • 第11次添加,原来数组的容量是10,不够用了,扩容1.5倍,扩容为长度为15的数组,执行添加操作

    • ArrayList数组当原来的数组不够用的时候,才会扩容

ArrayList源码分析

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
​
    //默认的数组长度
    private static final int DEFAULT_CAPACITY = 10; 
    
    private static final Object[] EMPTY_ELEMENTDATA = {};
    
    //3. 默认空数组,在通过无参构造方法创建ArrayList对象时,赋值给elementData
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    
    //1. ArrayList存放添加值的地方  它是一个Object类型的数组
    transient Object[] elementData;
    
    private int size;
    
    //ArrayList集合中的元素也是有上限的
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
    
   //2. 无参构造方法   执行无参构造方法,创建ArrayList对象
   public ArrayList() {
        //初始化elementData
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    
   //4.执行添加元素操作
   public boolean add(E e) {
       //5. 确认数组的长度是否够用
        ensureCapacityInternal(size + 1); 
       
       //9. 真正的添加操作
        elementData[size++] = e;
        return true;
    }
    
   //5. 确认数组长度
   private void ensureCapacityInternal(int minCapacity) {
       //7. 判断是扩容
        ensureExplicitCapacity( calculateCapacity(elementData, minCapacity) );
    }
    
    /*
     *  6、 计算容量
     *  - 当第一次执行时,返回值为10
     *  - 以后每次,都是直接返回minCapacity值
     */
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        //只有当第一次添加添加元素时,elementData才为空数组
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
   } 
    
   //7. 判断容量是否扩容
   private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
​
        // 只要在数组不够用的时候,才会进行扩容
        if (minCapacity - elementData.length > 0) {
            //8. 扩容数组
             grow(minCapacity);
        }
           
   }
    
  //8. 扩容数组
  private void grow(int minCapacity) {
        // 获取原来数组的长度   0,10
        int oldCapacity = elementData.length;
        //计算后的新长度   0,15
        int newCapacity = oldCapacity + (oldCapacity >> 1);
      
        //只有第一次添加的时候才会成立
        if (newCapacity - minCapacity < 0)  
            newCapacity = minCapacity;
      
        //判断数组的容量是否达到最大值
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
      
        // 扩容数组, 第一次时,扩容为长度为10,以后每次扩容为原来的1.5倍
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
​
}
​

2.2 LinkedList集合

LinkedList是List接口的一个实现类,底层是一个链表,是一个双向链表

链表是由一个一个的链子组成,链子就是Node对象

 

public class LinkedList<E> extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{ 
    
    transient int size = 0;
    
    //链表的第一个链子
    transient Node<E> first;
    
    //链表的最后一个链子
    transient Node<E> last;
    
    public LinkedList() {
    }
    
    //添加元素
    public boolean add(E e) {
        linkLast(e);
        return true;
    }
    
    void linkLast(E e) {
        //获取最后一个链子(Node对象)
        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++;
    }
    
    
    
    
    //链子   双向链表
    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;
        }
    }
    
    
    
    
}

2.3 Vector集合

Vector的底层也是一个数组,只不过它是线程安全的。

2.4 比较ArrayList和LinkedList

ArrayList底层是数组:查询的速度快,删除,和插入的速度慢

LinkedList底层是一个链表:查询效率低,删除和插入的速度快

Vector是线程安全的,效率比ArrayList低,适合使用在多线程的编程条件下。

3. Set集合

Set是Collection的子接口,无序不可重复

无序:有顺序,没有序号

不可重复:值不能重复(可以自定义重复的规则)

public interface Set<E> extends Collection<E> { 
    
    //基本和Colletion接口一样
​
}

3.1 HashSet

HashSet是Set集合的一个实现类,底层是HashMap

可以使用增强型for循环进行遍历

package com.qfedu;
​
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
​
public class Demo06 {
​
    public static void main(String[] args) {
        
        /*
         * Set集合
         * HashSet实现
         */
        
        //初始化
        Set<Integer> set = new HashSet<Integer>();
        
        //添加元素
        set.add(9);
        set.add(19);
        set.add(18);
        set.add(76);
        
        /*
         * 增强型for循环
         * 
          for(泛型 变量 : 集合) {
            System.out.println(变量);
          }
          
           集合会把元素依次赋值给变量,在for循环中执行
           
         * 
         */
        for(Integer i : set) {
            System.out.println(i);
        }
        
        
    }
}

3.2 TreeSet

TreeSet也是Set的实现类,会自动为元素进行排序

注意 : TreeSet是为元素排序的一个非常好的一种方法,

如果实现一个类的两个对象是可比较的,比较的目的是为了排序

如何定义两个对象比较的规则,这个类需要实现Comparable接口

我们常见的一些类,比如Integer,String等类都实现了Comparable接口定义了两个对象比较的方式

public interface Comparable<T> { 
    
    /*
     *  正整数>你    零 =你     负整数<你
     */
    public int compareTo(T o);
}
package com.qfedu;
​
import java.util.Set;
import java.util.TreeSet;
​
public class Demo06_2 {
​
    public static void main(String[] args) {
        
        /*
         * Set集合
         * TreeSet实现类:TreeSet会自动为元素排序
         */
        
        Set<Integer> set = new TreeSet<Integer>();
        
        //添加元素
        set.add(9);
        set.add(19);
        set.add(10);
        set.add(76);
        
        for(Integer i : set) {
            System.out.println(i);
        }
        
        
        Set<Student> set2 = new TreeSet<Student>();
        
        set2.add(new Student(99, "jackma","111"));
        set2.add(new Student(100, "pony","121"));
        set2.add(new Student(99, "tomlei","131"));
        set2.add(new Student(98, "james","131"));
        
        for(Student s : set2) {
            System.out.println(s);
        }
        
    }
}
​
class Student implements Comparable<Student>{
    private Integer score;
    private String name;
    private String code; // 学号
    
    public Student() {
    }
    
    public Student(Integer score, String name) {
        super();
        this.score = score;
        this.name = name;
    }
    
    public Student(Integer score, String name, String code) {
        super();
        this.score = score;
        this.name = name;
        this.code = code;
    }
​
    public Integer getScore() {
        return score;
    }
    public void setScore(Integer score) {
        this.score = score;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    public String getCode() {
        return code;
    }
​
    public void setCode(String code) {
        this.code = code;
    }
​
    @Override
    public String toString() {
        return "Student [score=" + score + ", name=" + name + ", code=" + code + "]";
    }
​
    @Override
    public int compareTo(Student o) {
        //根据成绩进行排序
    //  return this.score - o.getScore();
        
        //根据名字排序
    //  return this.name.length() - o.getName().length();
        
        //根据成绩降序排
    //  return o.getScore() - this.score ;
        
        
        /*
         * 先根据姓名的长度进行排序
         * 1. 如果学生的姓名长度是相等,再根据成绩进行排序
         * 2. 如果成绩也相等,那就根据学号进行排序
         */
        
        if(this.name.length() != o.getName().length() ) {
            return this.name.length() - o.getName().length();
        } else if(this.score != o.getScore()) {
            return this.score - o.getScore();
        } else {
            /*
             * 字符串的比较
             *  参考源码,从第一个字符开始比较,相减
             */
            return this.code.compareTo(o.getCode());
        }
        
    }
    
}

4. 内部类

  • 成员内部类

    • 直接定义在类中

  • 静态内部类

    • 由static修饰的成员内部类

  • 局部内部类

    • 定义在方法中的类

  • 匿名内部类

    • 直接把接口的实现定义在接口的实例化中

package com.qfedu;
​
public class Demo03 {
​
    private String a;
    private String b;
    private static int c;
    
    
    //1. 成员内部类,直接定义在类中
    class InnerClass {
        
        private String d;
    //  private static String e;    //不允许创建静态属性
        
        public void print() {
            System.out.println(a+c);
        }
    }
    
    //2. 静态内部类,由static修饰的成员内部类
    static class InnerStaticClass {
        
        //可以定义静态属性
        private static String e;
        
        //可以操作外部类静态属性
        public void print() {
            System.out.println(e+c);
        }
    }
    
    
    public void test() {
        
        
        //3. 定义在方法中类,局部内部类
        class PartClass {
            
        }
        
        PartClass pc = new PartClass();
    }
    
    
    
    public static void main(String[] args) {
        A a = new B();
        a.aa();
        
        //4. 匿名内部类,不考虑代码的可复用性,就爽这一次
        A a2 = new A() {
            @Override
            public void aa() {
                System.out.println("在这里实现aa抽象方法---");
            }
        };
        
        a2.aa();
    }
    
}
​
interface A {
    void aa();
}
​
class B implements A {
​
    @Override
    public void aa() {
        System.out.println("实现aa");
        
    }
    
}

5. Map集合

Map是一种键值对(K-V),每一个值都会有一个名字

public interface Map<K,V> { 
​
    //键值对个数
    int size();
    
    boolean isEmpty();
    
    //是够存在key
    boolean containsKey(Object key);
    
    //是够存在value
    boolean containsValue(Object value);
    
    V get(Object key);
    
    V put(K key, V value);
    
    V remove(Object key);
    
    void clear();
    
    //获取所有的key得到一个set集合
    Set<K> keySet();
    
    //获取键值对的集合
    Set<Map.Entry<K, V>> entrySet();
    
    
    //内部类  表示一个对
    interface Entry<K,V> { 
        K getKey();
        V getValue();
    }
    
}

package com.qfedu;
​
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
​
public class Demo07 {
​
    public static void main(String[] args) {
        /*
         * 定义一个Map集合
         *  K : String   表示键只能定义字符串
         *  V : Integer   只能保存整数的值
         *  
         *  每次在保存值时,保存是一对,有名字有值
         */
        Map<String, Integer> map = new HashMap<String, Integer>();
        
        
        /*
         * 保存值
         * 
         * put(k,v);
         * 
         * k:不允许重复,后面添加的会覆盖掉前面的值
         * k,v值可以为null
         *  
         */
        map.put("jackma", 100);
        map.put("pony", 90);
        map.put("tomlei", 120);
        map.put("tomlei", 130);
        map.put(null, null);
        
        System.out.println(map.size());
        System.out.println(map.get("tomlei"));
        
        
        /*
         * 获取值
         * 
         * 可以根据key获取对应的value
         * 
         * V get(Object key);
         */
        Integer v1 = map.get("jackma");
        Integer v2 = map.get("kkk");
        System.out.println(v1);
        System.out.println(v2);   // 没有该key,返回null
        
        
        System.out.println("-------------------------");
        
        //遍历  先获取k,然后通过k获取v
        Set<String> keySet = map.keySet();
        for(String k : keySet) {
            System.out.println(k + ":"+ map.get(k));
        }
        
        System.out.println("-------------------------");
        
        Set<Entry<String, Integer>> entrySet = map.entrySet();
        for(Entry<String, Integer> e : entrySet) {
            System.out.println(e.getKey()+":"+ e.getValue());
        }
        
​
        
    }
}

5.1 HashMap

HashMap的底层是数组加链表(单向链表)

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {
    
    //初始化容量
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;  // 16
 
    //最大容量
    static final int MAXIMUM_CAPACITY = 1 << 30;
    
    //加载因子   扩容的时机
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    
    //树化的阈值
    static final int TREEIFY_THRESHOLD = 8;
    
     //反树化的阈值
    static final int UNTREEIFY_THRESHOLD = 6;
    
    //树化的最小容量
    static final int MIN_TREEIFY_CAPACITY = 64;
    
    //链表的数组  HashMap的底层的主结构就是链表的数组
    transient Node<K,V>[] table;
    
    //键值对的个数
    transient int size;
    
    //链表  单项链表
    static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;
​
        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
​
    }
    
    //红黑树
    static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
        TreeNode<K,V> parent;  // red-black tree links
        TreeNode<K,V> left;
        TreeNode<K,V> right;
        TreeNode<K,V> prev;    // needed to unlink next upon deletion
        boolean red;
        TreeNode(int hash, K key, V val, Node<K,V> next) {
            super(hash, key, val, next);
        }
    }
 
    
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值