JAVA集合(二)

JAVA集合(二)

一、Collection子接口之一:List接口

使用Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals().

1、List接口概述

image-20220419170406854

2、面试题:ArrayList、LinkedList、Vector三者的异同?
同:
三个类都实现了List接口,存储数据的特点相同:存储有序的、可重复的数据
不同:
ArrayList:List接口的主要实现类;线程不安全,效率高;底层源码是Object[] elementData存储
LinkedList:对于频繁的插入、删除操作。使用此类效率比Arraylist高;底层使用双向链表存储
Vector:List接口的古老实现类;线程安全的,效率低;底层源码Object[]存储 elementData存储

3、ArrayList的源码分析

JDK 7情况下:

image-20220420155810598

JDK 8情况下:

ArrayList list=new ArrayList(); 底层Object[] elementData初始化为{},并没有创建长度为10的数组

list.add(123); 第一次调用add()时,底层才创建了长度10的数组,并将数组123添加到elementData[0]

小结:jdk7中的ArrayList的对象创建类似于单例的饿汉式,而Jdk8中的ArrayList的对象的创建类似于单例的懒汉式,延迟了数组的创建,节省内存。

4、linkedList的源码分析:

LinkedList list =new LinkedList(); 内部声明了Node类型的first和last属性,默认为null。

list(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=item;
        this.next=next;
        this.prev=prev;
    }
}

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

二、List实现类之二:LinkList接口及List接口常用方法

image-20220421174432482

image-20220421174544863

举例1:

  @Test
    public void test1(){
        ArrayList list = new ArrayList();
        list.add(123);
        list.add(456);
        list.add("AA");
        list.add(new Person("Tom",12));
        list.add(456);

        System.out.println(list);

        //1.viod add(int index,Object ele);在index位置插入ele元素
        list.add(1,"BB");
        System.out.println(list);
        System.out.println("==================");
        //2.boolean addAll(int index,Collection eles);从index位置开始键eles中所有元素添加
        List list1=Arrays.asList(1,2,3);
        list.addAll(list1);
        //注意区别 list.add(list);
        System.out.println(list);
        System.out.println(list.size());//6+3=9

        //3.Object get(int index);获取指定index位置的元素
        System.out.println(list.get(2));
    }

举例2:

@Test
    public void test02(){
        ArrayList list = new ArrayList();
        list.add(123);
        list.add(456);
        list.add("AA");
        list.add(new Person("Tom",12));
        list.add(456);

        //4.int indextOf(Object obj);返回obj在集合中首次出现的位置
        int index=list.indexOf(456);
        System.out.println(index);//存在输出是1,否则输出是-1

        //5int lastindexOf(Object obj);返回obj在集合中末次出现的位置
        System.out.println(list.lastIndexOf(456));//存在输出是元素所在的索引位置,否则输出是-1

        System.out.println("===========");
        //6.Object remove(int index);移除指定index位置的元素
        Object obj = list.remove(0);
        System.out.println(obj);//元素的位置
        System.out.println(list);//删除之后所有元素都会迁移

        //7.Object set(int index,Object ele);设置指定index位置的元素为ele
        list.set(1,"cc");
        System.out.println(list);

        //8.List sublist(int fromIndex,int toIndex);返回从fromIndex到toIndex位置的左闭右开子集合
        List subList=list.subList(2,4);
        System.out.println(subList);

    }

总结:常用方法

增:add(Object obj)

删:remove(int index) / remove(Object obj)

改:set(int index,Object ele)

查:get(int index)

插:add(int index,Object ele)

长度:size()

遍历: Iterator迭代器   、增强for循环、普通循环遍历

遍历举例:

 @Test
    public void test03(){
        ArrayList list = new ArrayList();
        list.add(123);
        list.add(456);
        list.add("AA");

        //方式一:Iterator迭代器方式
        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println("-------------------");
        //方式二:增强for循环
        for(Object obj:list){
            System.out.println(obj);
        }
        System.out.println("-------------------");
        //方式三:普通for循环
        for (int i = 0; i <list.size() ; i++) {
            System.out.println(list.get(i));
        }
    }
三、Collection子接口之二:Set接口

1、Set接口概述

image-20220422173804258

image-20220422173926455

image-20220422174013846

image-20220422174047479

2、set接口的框架

set接口:存储无序的、不可重复的数据

HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值

LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历

TreeSet:可以按照添加对象指定属性,进行排序。

⑴HashSet的使用:

 /*
    一、
    Set:存储无序的、不可重复的数据
    以HashSet为例说明:
    1.无序性:不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值决定的。

    2.不可重复性:保证添加的元素按照equals()判断时,不能返回true。即:相同的元素只能添加一个。

    二、添加元素的过程:以HashSet为例
     我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,
     此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即:索引位置):判断
     数组此位置上是否已经有元素:
        如果此位置上没有其他元素,则元素a添加成功。---》情况1
        如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值:
            如果hash值不相同,则元素a添加成功。---》情况2
            如果hash值相同,进而需要调用元素a所在类的equals()方法:
                 equals()返回ture,元素a添加失败
                 equals()返回false,则元素a添加成功。--》情况3

     对于添加成功的情况2和情况3而言:元素a与已经存在指定索引位置上数据以连接表的方式存储
        jdk7:元素a放到数组中,指向原来的元素
        jdk8:原来的元素在数组中,指向元素a
        总结:七上八下
        
        HashSet底层:数组+链表的结构
     */
    @Test
    public void test1(){
        Set set = new HashSet();
        set.add(456);
        set.add(123);
        set.add("AA");
        set.add("BB");
        set.add(new User("Tom",11));
        set.add(new User("Tom",11));
        set.add(789);

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

①set接口中没有额外定义新的方法,使用的都是Collection中声明过的方法。

②要求:向Set中添加的数据,其所在的类一定要重写hashCode ()和equals()

要求:重写的hashCode()和equals()尽可能保持一致:想等的对象必须具有相等的散列码。

image-20220423103515180


image-20220423103737877

⑵LinkHashSet的使用:

LinkHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,记录数据前一个数据和后一个数据。

优点:对于频繁的遍历操作,LinkHashSet效率高于HashSet

image-20220423151725085

⑶TreeSet的使用:

①向TreeSet中添加的数据,要求是相同类的对象。

②两种排序方式:自然排序(实现comparable接口)和定制排序(Comparator接口)

③自然排序中,比较两个对象是否相同的标准为:compareTo()返回0,不再是equals()。

④定制排序中,比较两个对象是否相同的标准为:compare()返回0,不再是equals()。

image-20220423163529962

自然排序(实现comparable接口)举例:

 //按照姓名从小到大排列,年龄从小到大排列
    @Override
    public int compareTo(Object o) {
        if (o instanceof User){
            User user=(User)o;
           /*
            return this.name.compareTo(user.name);
            //从大到小
            //return -this.name.compareTo(user.name);
            */

            int compare=-this.name.compareTo(user.name);
            if (compare!=0){
                return compare;
            }else{
                return Integer.compare(this.age, user.age);
            }
        }else{

            throw new RuntimeException("输入的类型不匹配");
        }

    }
 @Test
    public void test(){
        TreeSet set = new TreeSet();
        /*
        //失败:不能添加不用类的对象
        set.add(123);
        set.add("AA");
        set.add(new User("Tom",12));
         */
        /*
        //举例一:结果从下到大输出
        set.add(123);
        set.add(-6);
        set.add(8);
        set.add(89);
         */

        //举例二:
        set.add(new User("Tom",12));
        set.add(new User("AA",2));
        set.add(new User("BB",8));
        set.add(new User("CC",10));
        set.add(new User("CC",8));

        //快捷键  迭代器遍历 itit
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Object next =  iterator.next();
            System.out.println(next);
        }
    }

定制排序(Comparator接口)举例:

 @Test
    public void test2(){
        Comparator com=new Comparator() {
           //按照年龄从小到大排列,年龄一样就不要了

            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof User && o2 instanceof User){
                    User u1=(User)o1;
                    User u2=(User)o2;
                    return Integer.compare(u1.getAge(), u2.getAge());
                }else {
                    throw new RuntimeException("输入的类型不一致");
                }
            }
        };
        //不加参数按照自然排序的方式,加上参数按照参数的排列顺序来
        TreeSet set = new TreeSet(com);
        set.add(new User("Tom",12));
        set.add(new User("AA",2));
        set.add(new User("BB",8));
        set.add(new User("CC",10));
        set.add(new User("CC",8));
        //快捷键  迭代器遍历 itit
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Object next =  iterator.next();
            System.out.println(next);
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小橙子*

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值