day11-JAVA集合框架、collection(list、set)、迭代器、增强for循环、list接口(ArrayList、LinkedList和Vector)、Set接口(HS、LHS、TS)

1.集合框架

数组初始化后长度确定-------------------------不便于扩展

声明的类型,决定初始化类型

提供属性方法少,不便于添加、删除、插入操作,效率不高,无法直接获取存储元素个数

数组存储的数据是有序、可以重复的


Java 集合可分为 Collection Map 两种体系
Collection 接口: 单列数据,定义了存取一组对象的方法的集合
        List 元素有序、可重复的集合
        Set 元素无序、不可重复的集合
Map 接口: 双列数据,保存具有映射关系“ key-value对”的集合        


2.Collection接口方法

Collection 接口是 List Set Queue 接口的父接口,该接口里定义的方法既可用于操作 Set 集合,也可用于操作 List Queue 集合。
JDK 不提供此接口的任何直接实现,而是提供更具体的子接口 ( 如: Set List)实现。
Java5 之前, Java 集合会丢失容器中所有对象的数据类型,把所有对象都当成 Object 类型处理;从 JDK 5.0 增加了 泛型 以后, Java 集合可以记住容器中对象的数据类型。
@Test
    public void Test(){
        Collection collection = new ArrayList();
        Collection collection1 = new ArrayList();

        //1.添加元素
        collection.add(123);
        collection.add("asd");
        collection.add(new Date());

        collection1.addAll(collection);//添加一个集合

        //2.获取有效元素个数
        int num = collection.size();
        System.out.println(num);

        //3.是否空集合
        System.out.println(collection.isEmpty());

        //4.是否包含某个元素
        System.out.println(collection.contains(123));
        System.out.println(collection.containsAll(collection1));//比较两个集合是否相等
        System.out.println("----------------------");

        //5.删除某个元素
        collection.remove(123);
        System.out.println(collection.size());

        collection1.removeAll(collection);//删除相同的元素
        System.out.println(collection1.size());

        //6.取两个集合的交集
        System.out.println(collection);//[asd, Tue Feb 22 22:42:34 CST 2022]
        System.out.println(collection1);//[123]
        collection.retainAll(collection1);//取两个集合的交集,并保存在前面的集合中,所以collection变成空的了
        System.out.println(collection);//[]

        //7.判断集合是否相等
        System.out.println(collection.equals(collection1));//false 不相等
        System.out.println("=================");

        //8.集合-》数组
        collection1.add("sadad");
        Object [] arr=collection1.toArray();
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
        System.out.println("++++++++++++++++++++++++");

        //9。返回当前对象的hash值
        System.out.println(collection1.hashCode());//109198623

        //10.数组-》集合  Arrays.asList()
        List list = Arrays.asList(new int[]{12,33,24});
        System.out.println(list);
        List list1 = Arrays.asList(new Integer[]{12,33,24});
        System.out.println(list1);
        List list2 = Arrays.asList(new String[]{"12","33","24"});
        System.out.println(list2);
        List list3 = Arrays.asList("12SSD","ADSDsA","ASD3");
        System.out.println(list3);


    }

3.迭代器接口Iterator

//迭代器测试iterator
    @Test
    public void Test1(){
        //1.迭代器只用于遍历集合,首先要有一个集合
        Collection collection = new ArrayList();
        collection.add("22dd");
        collection.add("vssdv");
        collection.add(123);

        //2.需要迭代器对象
        Iterator iterator = collection.iterator();

        //3.迭代器是指针形式,需要先判断指针指向的下一个元素是否为空?
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
//迭代器测试remove
    @Test
    public void Test2(){
        Collection collection = new ArrayList();//list存放有序、可重复的数据
        collection.add(123);
        collection.add(456);
        collection.add("qwe");
        collection.add("asd");
        collection.add(123);
        collection.add("qwe");

        Iterator iterator = collection.iterator();

        while (iterator.hasNext()){
            Object o = iterator.next();
            if ("qwe".equals(o)){
                iterator.remove();
            }
        }

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

@Test
    public void Test3(){
        Collection collection = new ArrayList();
        collection.add("123");
        collection.add("qwe");
        collection.add(123);

        for (Object obj : collection) {
            System.out.println(obj);
        }
    }

4.List接口,有序(按照添加顺序)、可重复

JDK API List 接口的实现类常用的有: ArrayList LinkedList Vector
1.ArrayList:线程不安全,效率高,使用数组存储
2.LinkedList:使用双向链表存储,对于频繁的插入、删除效率高
3.Vector:线程安全,效率低,使用数组存储

1.ArrayList 

 /** 
 * .ArrayList的源码分析:
 *   1 jdk 7情况下,先创建一个长度为10的数组
 *      ArrayList list = new ArrayList();//底层创建了长度是10的Object[]数组elementData
 *      list.add(123);//elementData[0] = new Integer(123);
 *      ...
 *      list.add(11);//如果此次的添加导致底层elementData数组容量不够,则扩容。
 *      默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中。
 *
 *      结论:建议开发中使用带参的构造器:ArrayList list = new ArrayList(int capacity)
 *
 *   2 jdk 8中ArrayList的变化:添加元素时才创建长度为10的数组
 *      ArrayList list = new ArrayList();//底层Object[] elementData初始化为{}.并没有创建长度为10的数组
 *
 *      list.add(123);//第一次调用add()时,底层才创建了长度10的数组,并将数据123添加到elementData[0]
 *      ...
 *      后续的添加和扩容操作与jdk 7 无异。
 *   3 小结:jdk7中的ArrayList的对象的创建类似于单例的饿汉式,而jdk8中的ArrayList的对象
 *            的创建类似于单例的懒汉式,延迟了数组的创建,节省内存。
 * 
 */

 2.LinkedList

  • 对于频繁的插入或删除元素的操作,建议使用LinkedList类,效率较高
  • LinkedList:双向链表,内部没有声明数组,而是定义了Node类型的first和last,用于记录首末元素。同时,定义内部类Node,作为LinkedList中保存数据的基本结构。

/**
  * 3.LinkedList的源码分析:
  *       LinkedList list = new LinkedList(); 内部声明了Node类型的first和last属性,默认值为null
  *       list.add(123);//将123封装到Node中,创建了Node对象。
  *
  *       其中,Node定义为:体现了LinkedList的双向链表的说法
  *       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;     //next变量记录下一个元素的位置
  *            this.prev = prev;     //prev变量记录前一个元素的位置
  *            }
  *        }
  */
 

参考链接:https://blog.csdn.net/PorkBird/article/details/113727330 

3.Vector

Vector 是一个古老的集合,JDK1.0就有了。大多数操作与ArrayList相同,区别之处在于Vector是线程安全的。
在各种list中,最好把ArrayList作为缺省选择。当插入、删除频繁时,使用LinkedList;Vector总是比ArrayList慢,所以尽量避免使用。


/** 
  * 4.Vector的源码分析:jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组。
  *      在扩容方面,默认扩容为原来的数组长度的2倍。
  */ 

List接口常用方法

//List接口常用方法
    @Test
    public void Test4(){
        //增:add(int index, Object ele):在index位置插入ele元素
        //删:Object remove(int index):移除指定index位置的元素,并返回此元素
        //改:Object set(int index, Object ele):设置指定index位置的元素为ele
        //查:Object get(int index):获取指定index位置的元素

        //boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
        //int indexOf(Object obj):返回obj在集合中首次出现的位置
        //int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
        //List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合


        ArrayList arrayList = new ArrayList();
        //1.增
        arrayList.add(123);
        arrayList.add("asdf");
        arrayList.add("rrgb");
        arrayList.add(1,"nihao");
        System.out.println(arrayList);

        //2.删
        arrayList.remove(1);
        System.out.println(arrayList);

        //3.改
        arrayList.set(1,"nihao");
        System.out.println(arrayList);

        //4.查
        Object obj=arrayList.get(1);
        System.out.println(obj);

        //5.boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
        ArrayList arrayList1 = new ArrayList();
        arrayList1.add(999);
        arrayList1.add(999);
        arrayList1.add(999);
        arrayList.addAll(1,arrayList1);
        System.out.println(arrayList);

        //6.int indexOf(Object obj):返回obj在集合中首次出现的位置
        //7.int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
        int startIndex = arrayList.indexOf(999);
        System.out.println(startIndex);
        int endIndex = arrayList.lastIndexOf(999);
        System.out.println(endIndex);

        //8.List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
        List sublist = arrayList.subList(1,5);
        System.out.println(sublist);

    }
@Test
    public void Test5(){
        // 对于频繁的插入或删除元素的操作,建议使用LinkedList类,效率较高
        // 新增方法:
        // void addFirst(Object obj)
        // void addLast(Object obj)
        // Object getFirst()
        // Object getLast()
        // Object removeFirst()
        // Object removeLast()
        LinkedList linkedList = new LinkedList();
        linkedList.add(123);
        linkedList.add("adas");
        linkedList.add("uuu");

        linkedList.addFirst(999);
        linkedList.addLast(999);
        System.out.println(linkedList);

        System.out.println(linkedList.getFirst());
        System.out.println(linkedList.getLast());

        Object obj = linkedList.removeFirst();
        System.out.println(obj);
        obj = linkedList.removeLast();
        System.out.println(obj);
        System.out.println(linkedList);
    }

面试题:

   /**
     * 请问ArrayList/LinkedList/Vector的异同?谈谈你的理解?
     * ArrayList底层是什么?扩容机制?Vector和ArrayList的最大区别?

     * 
     * ArrayList和LinkedList的异同二者都线程不安全,相对线程安全的Vector,执行效率高。
     * 此外,ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
     * 对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
     * 对于新增和删除操作add(特指插入)和remove,LinkedList比较占优势,因为ArrayList要移动数据。
     * 
     * ArrayList和Vector的区别Vector和ArrayList几乎是完全相同的,
     * 唯一的区别在于Vector是同步类(synchronized),属于强同步类。
     * 因此开销就比ArrayList要大,访问要慢。正常情况下,
     * 大多数的Java程序员使用ArrayList而不是Vector,
     * 因为同步完全可以由程序员自己来控制。Vector每次扩容请求其大小的2倍空间,
     * 而ArrayList是1.5倍。Vector还有一个子类Stack。
     */

 


5.set接口,无序(不按照添加顺序,根据数据哈希值排序)、不可重复

/**
 * 1.Set接口的框架:
 * |----Collection接口:单列集合,用来存储一个一个的对象
 *          |----Set接口:存储无序的、不可重复的数据   -->高中讲的“集合”
 *             |----HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值
 *                 |----LinkedHashSet:作为HashSet的子类;遍历其内部数据时,
可以按照添加的顺序遍历
 *                                    对于频繁的遍历操作,LinkedHashSet效率高于HashSet.
 *             |----TreeSet:可以按照添加对象的指定属性,进行排序。
 */

 1.HashSet

HashSet 具有以下特点:
        不能保证元素的排列顺序
        HashSet 不是线程安全的
        集合元素可以是 null
HashSet 集合判断两个元素相等的标准 两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。
对于存放在 Set 容器中的对象, 对应的类一定要重写 equals() hashCode(Object obj) 方法,以实现对象相等规则。即:“相等的对象必须具有相等的散列码”。
  • 底层也是数组,初始容量为16,当如果使用率超过0.75,(16*0.75=12)就会扩大容量为原来的2倍。(16扩容为32,依次为64,128…等)
  • 数组+链表的结构。

 

 添加元素的过程:以HashSet为例:
     *      我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,
     *      此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置),判断
     *      数组此位置上是否已经有元素:
     *          如果此位置上没有其他元素,则元素a添加成功。 --->情况1
     *          如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值:
     *              如果hash值不相同,则元素a添加成功。--->情况2
     *              如果hash值相同,进而需要调用元素a所在类的equals()方法:
     *                    equals()返回true,元素a添加失败
     *                    equals()返回false,则元素a添加成功。--->情况2
     *
     *      对于添加成功的情况2和情况3而言:元素a 与已经存在指定索引位置上数据以链表的方式存储。
     *      jdk 7 :元素a放到数组中,指向原来的元素。
     *      jdk 8 :原来的元素在数组中,指向元素a
     *      总结:七上八下
原文链接:https://blog.csdn.net/PorkBird/article/details/113727330

 关于hashCode()和equals()的重写:https://blog.csdn.net/PorkBird/article/details/113727330


 2.LinkedHashSet

LinkedHashSet HashSet 的子类
LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,
但它同时使用双向链表维护元素的次序,这使得元素看起来是以 插入顺序保存 的。
LinkedHashSet 插入性能略低于 HashSet 但在迭代访问 Set 里的全部元素时有很好的性能。
LinkedHashSet 不允许集合元素重复。
数组+双向链表

3.TreeSet

TreeSet SortedSet 接口的实现类, TreeSet 可以确保集合元素处于排序状态。
TreeSet 底层使用 红黑树 结构存储数据
新增的方法如下: ( 了解 )
Comparator comparator()
Object first()
Object last()
Object lower(Object e)
Object higher(Object e)
SortedSet subSet(fromElement, toElement)
SortedSet headSet(toElement)
SortedSet tailSet(fromElement)
TreeSet 两种排序方法: 自然排序 定制排序 。默认情况下, TreeSet 采用自然排序。

 

 1.自然排序:不能向TreeSet里面添加不同类型的元素

自然排序 TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序( 默认情况 ) 排列
如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现 Comparable接口
实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过compareTo(Object obj) 方法的返回值来比较大小。
 Comparable 的典型实现:
BigDecimal BigInteger 以及所有的数值型对应的包装类:按它们对应的数值大小进行比较
Character :按字符的 unicode 值来进行比较
Boolean true 对应的包装类实例大于 false 对应的包装类实例
String :按字符串中字符的 unicode 值进行比较
Date Time :后边的时间、日期比前面的时间、日期大
为什么重写compareTo方法同时重写equals方法?
与HashSet不同,TreeSet插入元素时的判断标准其实只需要实现Comparable接口的compareTo()方法就可以了,但是一般情况了,我们推荐同时重写实现equals()这个方法,原因在于我们写这个类的时候,无法确认在后面的情况下,会不会用到equals()方法,比如可能会要把这个类的实例加入到HashSet中?这是可能出现的,我们当然不希望出现compareTo()方法得到的结果为0,但是equals()方法得到的却是flase这样的奇怪情况出现,所以一般实现compareTo()时会同时重写equals()来保证两个方法的结果一致,不产生冲突。
 
class Student implements Comparable{
        //1.属性
        private int id;
        private String name;

        //2.构造器
        public Student(int id,String name){
            this.id=id;
            this.name=name;
        }
        //3.get/set方法
        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        //重写equals方法
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Student student = (Student) o;

            if (this.id!=student.id){
                return false;
            }else{
                if (this.name!=null){
                    return this.name.equals(student.name);
                }else {
                    return student.name==null;
                }
            }
        }

        @Override
        public int hashCode() {
            int result;
            if (this.name!=null){
                result=name.hashCode();
                result=31*result+this.id;
                return result;
            }else {
                result=0;
                result=31*result+this.id;
                return result;
            }
        }

        @Override
        public String toString() {
            return "Student{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    '}';
        }


        //学号从小到大,姓名从小到大
        //重写compareTo方法
        @Override
        public int compareTo(Object o) {
            if(o instanceof Student){
                Student s = (Student) o;
                int compare=-this.name.compareTo(s.name);//字符串比较的是unicode值大小,小于0放左面
                if (compare!=0){
                    return compare;
                }else {
                    return Integer.compare(this.id,s.id);
                }
            }else {
                throw new RuntimeException("输入的类型不匹配!");
            }
        }
    }

    @Test
    public void Test2(){
        Set set = new TreeSet();
        set.add(new Student(3,"KKK"));
        set.add(new Student(1,"zzz"));
        set.add(new Student(2,"zzz"));
        set.add(new Student(1,"zzz"));
        set.add(new Student(1,"www"));

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

2.定制排序

//TreeSet的定制排序:在什么条件下使用?若比较的对象没有实现compareable接口  或者  不希望按照默认情况进行排序,可以考虑定制排序,使用comparator接口,重写compare(a,b)方法,若a》b则返回正数

//TreeSet的定制排序:在什么条件下使用?若比较的对象没有实现compareable接口  或者  不希望按照默认情况进行排序
    //可以考虑定制排序,使用comparator接口,重写compare(a,b)方法,若a》b则返回正数
    @Test
    public void Test(){

        //按照年龄从小到大排序
        Comparator com = new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if(o1 instanceof Student && o2 instanceof Student){
                    Student s1 = (Student) o1;
                    Student s2 = (Student) o2;
                    return Integer.compare(s1.age,s2.age);
                }else {
                    throw new RuntimeException("输入的数据类型不正确");
                }
            }
        };

        TreeSet treeSet = new TreeSet(com);
        treeSet.add(new Student("QQQ",22));
        treeSet.add(new Student("www",11));
        treeSet.add(new Student("eee",33));

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

    }

    class Student {
        //1.属性
        private String name;
        private int age;

        //2.构造器
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }

        //3.get、set方法
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值