集合框架

Java集合框架详解

集合的概念

  • 概念:对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能
  • 和数组的区别
    • 数组长度固定,集合长度不固定
    • 数组可以存储基本类型和引用类型,集合只能存储引用类型(要使用基本类型可以对其进行装箱操作)
  • 位置:java.util.*;

Collection接口

        //创建集合,接口本身不能被实例化,new实现该接口的类
        Collection collection = new ArrayList();
        //添加元素
        collection.add("苹果");
        collection.add("香蕉");
        collection.add("榴莲");
        System.out.println("元素个数为:"+collection.size());
        System.out.println(collection.toString());
        //删除元素
        collection.remove("榴莲");
        System.out.println("删除后元素个数为:"+collection.size());
        //遍历元素,不能使用for,没有下标
       // collection.clear();
       // System.out.println(collection);
        for (Object o:collection) {
            System.out.println(o);
        }
        //使用迭代器(迭代器专门用来遍历集合的一种方式)
        //hasNext();有没有下一个元素
        //next();获取下一个元素
        //remove();删除当前元素
        System.out.println("------------");
        Iterator t = collection.iterator();
        while (t.hasNext()){
            String s = (String)t.next();
            System.out.println(s);
            //collection.remove(s);
            //t.remove();
        }
        System.out.println("元素个数:"+collection.size());
        //判断:
        System.out.println(collection.contains("苹果"));
        System.out.println(collection.isEmpty());

将存储对象由字符串换成对象

        Collection collection = new ArrayList();
        Student s1 = new Student("张三",20);
        Student s2 = new Student("李四",19);
        Student s3 = new Student("王五",18);
        collection.add(s1);//添加元素
        collection.add(s2);
        collection.add(s3);
        System.out.println("总元素个数为:"+collection.size());
/*        collection.remove(s1);
        System.out.println("总元素个数为:"+collection.size());*/
/*        for (Object o : collection) {
            Student s = (Student) o;
            System.out.println(s.toString());
        }*/
        Iterator iterator = collection.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println(collection.contains(s1));
        System.out.println(collection.isEmpty());

List接口与实现类

  • 特点:有序、有下标

  • 方法:

    • void add(int index, Object o)//在index位置插入对象
    • boolean addAll(int index,Collection c)//将一个集合中的元素添加到此集合中的index位置
    • Object get(int index)//返回集合中指定位置的元素
    • List subList(int fromIndex, int toIndex)//返回fromIndex和toIndex之间的集合元素
        List list = new ArrayList();
        list.add("小米");
        list.add("华为");
        list.add("苹果");
        list.add(0,"三星");
        System.out.println("元素个数为:"+list.size());
        System.out.println(list.toString());
        //删除元素
/*        list.remove(0);
        list.remove("小米");
        System.out.println(list.toString());*/
        //遍历
        System.out.println("--------使用for遍历--------");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        System.out.println("--------使用增强for遍历--------");
        for (Object o : list) {
            System.out.println(o);
        }
        //使用列表迭代器,和Iterator的区别,ListIterator,可以向前或者向后遍历,添加、删除、修改元素
        ListIterator listIterator = list.listIterator();
        System.out.println("----------使用迭代器从前往后----------");
        while (listIterator.hasNext()){
            System.out.println(listIterator.nextIndex()+":"+listIterator.next());
        }
        System.out.println("----------使用迭代器从后往前----------");//这个时候指针刚好指向最末端
        while(listIterator.hasPrevious()){
            System.out.println(listIterator.previousIndex()+":"+listIterator.previous());
        }
        //判断
        System.out.println(list.contains("三星"));
        System.out.println(list.isEmpty());
        //获取位置
        System.out.println(list.indexOf("华为"));

注意添加数字类会自动装箱

        List list  = new ArrayList();
        //添加数字会自动装箱
        list.add(20);
        list.add(30);
        list.add(40);
        list.add(50);
        list.add(60);
        System.out.println("元素个数为:"+":"+list.size());
        System.out.println(list.toString());
        //list.remove(new Integer(20));//表示的是下标不能直接使用数字,可以使用Object ,或者包装类(new一个)
        System.out.println();
        System.out.println("删除之后元素个数为:"+list.size());
        System.out.println(list.subList(1, 3));//含头不含尾

List实现类

  • ArraysList【重点】

    • 数组结构实现,查询块、增删慢;
    • JDK1.2版本,运行效率高、线程不安全
  • Vector

    • 数组结构实现,查询块、增删慢
    • JDK1.0版本,运行效率慢、线程安全
  • LinkedList:

    • 链表结构实现,增删快,查询慢。
  •  * ArrayList的用法
     * 存储结构:数组,查找遍历快,增删慢
             ArrayList arrayList = new ArrayList();
            Student s1 = new Student("张三",20);
            Student s2 = new Student("李四",21);
            Student s3 = new Student("王二",19);
            arrayList.add(s1);
            arrayList.add(s2);
            arrayList.add(s3);
            System.out.println("元素总数为:"+arrayList.size());
            arrayList.remove(new Student("张三",20));
            System.out.println("元素总数为:"+arrayList.size());
            //重写了equals方法,判断对象是否相等,判断是否为空,判断是否为同一类型,属性是否相等,默认返回false
            Iterator iterator = arrayList.iterator();
            while(iterator.hasNext()){
                Student s = (Student)iterator.next();
                System.out.println(s.toString());
            }
            ListIterator listIterator = arrayList.listIterator();
            System.out.println("-------使用列表迭代器--------");
            while (listIterator.hasNext()){
                System.out.println(listIterator.next());
            }
            while(listIterator.hasPrevious()){
                System.out.println(listIterator.previous());
            }
            //判断
            System.out.println(arrayList.contains(new Student("王二",19)));
            System.out.println(arrayList.indexOf(new Student("王二",19)));
    

    ArrayList()源码分析

    • m默认容量DEFAULT_CAPACITY = 10
    • 存放元素的数组:elementData
    • 实际元素个数:size
    • 如果没有在集合中添加任何元素,容量为0
    • 添加任意一个元素之后,容量为10
    • 每次扩容是原来的一点五倍
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
//-------------------------------------------
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    //-----------------------------------
        private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 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);
    }

Linkedlist


/**
 * LinkedList的使用
 * 存储结构:采用双向链表
 */
public class Demo01 {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        Student s1 = new Student("张三",20);
        Student s2 = new Student("李四",21);
        Student s3 = new Student("王二",19);
        linkedList.add(s1);
        linkedList.add(s2);
        linkedList.add(s3);
        System.out.println(linkedList.toString());
/*        linkedList.remove(new Student("张三",20));
        System.out.println("删除之后:"+linkedList.size());*/
        System.out.println("-----------for-------------");
        for (int i = 0; i < linkedList.size(); i++) {
            System.out.println(linkedList.get(i));
        }
        System.out.println("---------增强for-------------");
        for (Object o : linkedList) {
            Student s = (Student)o;
            System.out.println(s.toString());
        }
        System.out.println("---------迭代器-------------");
        Iterator iterator = linkedList.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

源码分析

​ int size:集合的大小

​ Node first:链表的头结点

​ Node last:链表的尾结点

    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++;
    }


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;
        }
    }

泛型和工具类

  • Java泛型是DJK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递
  • 常见形式有泛型类、泛型接口、泛型方法
  • 语法
    • <T,...>T称为类型占位符,表示一种引用类型
  • 好处
    • 提高代码的重用性
    • 防止类型转换异常,提高代码的安全性

使用泛型创建对象

        //使用泛型创建对象,不同类型的泛型对象不能相互赋值
        MyGeneric<String> myGeneric = new MyGeneric<String>();
        myGeneric.t = "你好世界";
        myGeneric.show("成功使用泛型");
        String s = myGeneric.getT();
        System.out.println(s);
        //实际类型只能是引用类型
        MyGeneric<Integer> myGeneric1 = new MyGeneric<>();
        myGeneric1.show(520);
        MyGeneric<String> myGeneric2 = myGeneric;
        System.out.println(myGeneric2.t);


泛型接口

/**
 * 使用泛型来创建接口
 * 语法:接口名<T>
 * 注意不能使用泛型静态常量
 * @param <T>
 */

public interface MyInterface<T> {
    String name = "pxt";
    T serve(T t);
}

public class MyInterfaceImpl implements MyInterface<String>{
    @Override
    public String serve(String s) {
        System.out.println(s);
        return s;
    }
}
//继承的类也可以使用泛型
public class MyInterfaceImpl2<T> implements MyInterface<T> {

    @Override
    public T serve(T t) {
        System.out.println(t);
        return t;
    }
}
//实例
        MyInterfaceImpl myInterface = new MyInterfaceImpl();
        myInterface.serve("使用泛型接口");
        MyInterfaceImpl2<Integer> myInterfaceImpl2 =new MyInterfaceImpl2();
        myInterfaceImpl2.serve(200);

泛型方法

/**
 * 泛型方法
 * 语法:<T>返回值类型
 */
public class MyGenericMethod {

    public <T>  T show(T t){
        System.out.println("泛型方法:"+t);
        return t;
    }
            MyGenericMethod myGenericMethod = new MyGenericMethod();
        myGenericMethod.show("成功使用了");
        myGenericMethod.show(3.1415926);
    //方法的类型取决于输入的数据

泛型集合

  • 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致
  • 特点
    • 编译时即可检查,而非运行时抛出异常
    • 访问时,不必类型转换(拆箱)
    • 不同泛型之间不能相互赋值,泛型不存在多态
        ArrayList<String> arrayList = new ArrayList();
        arrayList.add("第一个");
        arrayList.add("第二个");
        arrayList.add("第三个");
        for (String s : arrayList) {
            System.out.println(s);
        }
        ArrayList<Student> arrayList1 = new ArrayList<>();
        Student s1 = new Student("张三",20);
        Student s2 = new Student("李四",21);
        Student s3 = new Student("王二",19);
        arrayList1.add(s1);
        arrayList1.add(s2);
        arrayList1.add(s3);

        Iterator<Student> iterator = arrayList1.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

Set接口和实现类

  • 特点:无序、无下标、元素不可重复
  • 方法:全部继承自Collection中的方法
/**
 *测试set接口的使用
 * 无序,不可重复,乜有下标
 */
public class Demo01 {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
    }
    //和Collection一样的增加,删除,遍历,就是注意输入顺序和输出顺序无关
    //输入相同的元素会被无视
}

Set实现类

  • HashSet【重点】
    • 基于HashCode计算元素存放位置
    • 当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入

/**
 * HashSet的使用
 * 存储结构:哈希表(数组+链表+红黑树)
 * 存储过程:
 * (1)根据hashcode计算保存的位置,如果此位置为空,则直接保存,不为空则执行第二部
 * (2)再执行equals方法,如果equals方法为true,则认为是重复,否则,形成链表
 */
public class Demo03 {
    public static void main(String[] args) {
        HashSet<Person> hashSet = new HashSet<>();
        //添加数据
        Person p1 = new Person("刘德华",20);
        Person p2 = new Person("郭富城",19);
        Person p3 = new Person("梁朝伟",21);

        hashSet.add(p1);
        hashSet.add(p2);
        hashSet.add(p3);
        hashSet.add(new Person("刘德华",20));
        //没有名字的对象,地址不同被认为是不同元素

        System.out.println("元素个数为:"+hashSet.size());
    }
}

  • TreeSet
    • 基于排列顺序实现元素不重复
    • 实现了SortedSet接口,对集合元素自动排序
    • 元素对象的类型必须实现Comparable接口,指定排序规则
    • 通过CompareTo方法确定是否为重复元素
/**
 * 使用TreeSet保存数据
 * 存储结构:红黑树
 *要求:元素必须要实现Comparable接口,compareTo()方法返回值为0,认为是重复元素
 */
public class Demo04 {
    public static void main(String[] args) {
        TreeSet<Person> treeSet = new TreeSet<>();
        Person p1 = new Person("aaa",20);
        Person p2 = new Person("bbb",19);
        Person p3 = new Person("ccc",21);
        treeSet.add(p1);
        treeSet.add(p2);
        treeSet.add(p3);
        System.out.println("元素个数为:"+treeSet.size());
/*        treeSet.remove(new Person("梁朝伟",21));
        System.out.println("元素个数为:"+treeSet.size());*/
/*
        for (Person person : treeSet) {
            System.out.println(person.toString());
        }
*/
        Iterator<Person> iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

Comparato;实现定制比较器

/**
 * TreeSet集合的使用
 * Comparator;实现定制比较器
 * Comparable:可比较的(可以代替这个接口的作用)
 */
public class Demo05 {
    public static void main(String[] args) {
        TreeSet<Person> treeSet = new TreeSet<>(new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                int n1 = o1.getAge()- o2.getAge();
                int n2 = o1.getName().compareTo(o2.getName());
                return n1==0?n2:n1;
            }
        });//注意这个是在()里的函数

Map接口和实现类

  • 特点:存储一对数据(Key-Value),无序、无下标,键不可重复,值可重复

  • 方法

    • V put(K key,V value)//将对象存入到集合中,关联键值。key重复则覆盖原值
    • Object get(Object key)//根据键获取对应的值
    • Set //返回所有的key
    • Collection values() //返回包含所有值的Collection集合
    • Set<Map.Entry<K,V>>//键值匹配的Set集合
/**
 *Map接口的使用
 * 特点:(1)存储键值对(2)键不能重复,值可以重复(3)无序
 */
public class Demo01 {
    public static void main(String[] args) {
        //创建map集合
        Map<String,String>  map= new HashMap<>();
        //添加元素
        map.put("cn","中国");
        map.put("uk","英国");
        map.put("usa","美国");

        System.out.println("元素个数为:"+map.size());
/*        //删除元素
        map.remove("cn");
        System.out.println("元素个数为:"+map.size());*/
        //遍历元素
        System.out.println("----------使用keySet-----------");
       // Set<String> keySet = map.keySet();//使用keySet方法得到的是键值
        for (String s : map.keySet()) {
            System.out.println(s+":"+map.get(s));
        }
        System.out.println("--------使用entryKey-------");
        //Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String,String> entry : map.entrySet()) {
            System.out.println(entry.getKey()+":"+entry.getValue());
        }
        //判断
        System.out.println(map.containsKey("cn"));
        System.out.println(map.containsValue("泰国"));
    }
}

HashMap的实现

/**
 * HashMap的使用
 * 存储结构:哈希表(数组+链表+红黑树)
 * 使用和hashCode()和equals判断是否重复
 */
public class Demo02 {
    public static void main(String[] args) {
        HashMap<Student,String> students = new HashMap<>();
        Student s1 = new Student("孙悟空",101);
        Student s2 = new Student("沙和尚",102);
        Student s3 = new Student("猪八戒",103);
        students.put(s1,"斗战圣佛");
        students.put(s2,"卷帘大将");
        students.put(s3,"净坛使者");

      //  students.put(new Student("猪八戒",103),"净坛使者");
        System.out.println("元素个数为:"+students.size());
        System.out.println(students.toString());
        //删除
        //students.remove("s1");//按键删除
        //遍历
        System.out.println("-------使用keySet------");
        for(Student student:students.keySet()){
            System.out.println(student.toString()+":"+students.get(student));
        }
        System.out.println("--------使用entrySet------");
        for(Map.Entry<Student,String> entry:students.entrySet()){
            System.out.println(entry.getKey()+":"+entry.getValue());
        }
        //判断
        System.out.println(students.containsKey(new Student("孙悟空",101)));
        System.out.println(students.containsValue("弼马温"));
    }
}

源码分析

1 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;//hashMap初始容量大小
2 static final int MAXIMUM_CAPACITY = 1 << 30;//hashMap的数组的最大容量
3 static final float DEFAULT_LOAD_FACTOR = 0.75f;//默认加载因子
4 static final int TREEIFY_THRESHOLD = 8;//jdk1.8 当链表长度大于8时,调整成红黑树
5 static final int UNTREEIFY_THRESHOLD = 6;//jdk1.8 当链表长度小于6时,调整成链表
6 static final int MIN_TREEIFY_CAPACITY = 64;//jdk1.8 当链表长度大于8时,并且集合元素个数大于等于64时,调整为红黑树
7 transient Node<K,V>[] table;//哈希表中的数组
8 transient int size;//元素个数

总结:

(1)HashMap刚创建时,table是null,为了节省空间,当添加第一个元素时,table容量调整为16
(2)当元素个数大于阈值(16*0.75=12)时,会进行扩容,扩容后大小为原来的两倍,目的是减少调整元素的个数
(3)jdk1.8以前,链表时头插入,jdk1.8之后是未插入
    

Treemap

  • 和TreeSet的方法一样,需要构建比较的方法,要么让类对象实现Comparable接口,或者整Comparator类

image-20210913194908659

Collections工具类的使用

/**
 * 演示Collections的使用
 */
public class Demo01 {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(20);
        list.add(5);
        list.add(18);
        list.add(36);
        list.add(9);
        System.out.println("排序之前:"+list.toString());
        Collections.sort(list);
        System.out.println("排序之后:"+list.toString());
        Collections.reverse(list);
        System.out.println("翻转之后:"+list.toString());
        int i = Collections.binarySearch(list,13);
        System.out.println("查找的位置为:"+i);//找不到就显示负数
        List<Integer> list1 = new ArrayList<>();//长度为0,要长度相等才能copy成功
        for (int j = 0; j < list.size(); j++) {
            list1.add(0);
        }
        Collections.copy(list1,list);
        System.out.println("复制之后:"+list1.toString());
        Collections.shuffle(list);//每次都随机打乱
        System.out.println("打乱之后:"+list);
        //将list转为数组
        Integer[] arr = list.toArray(new Integer[0]);
        //小于等于原集合的长度生成的数组长度和集合一样,大于则以大的为准
        System.out.println("生成的数组的长度:"+arr.length+"数组为:"+ Arrays.toString(arr));
        //将数组转为List集合
        String[] strings = {"孙悟空","唐僧","猪八戒"};
        List<String> list2 = Arrays.asList(strings);
        //生成的集合是一个受限集合,不能添加和删除
        System.out.println(list2);
        Integer[] num = {1,23,48,541,84,11};
        //使用基本数据类型转化为集合要使用包装类
        List<Integer> list_num = Arrays.asList(num);
    }
}

前锋教育

posted @ 2021-10-07 17:16  肖寒*  阅读(59)  评论(0编辑  收藏  举报