Java集合(一)Collection接口

集合(一)Collection接口

一、Collection接口

  • Collection接口:单列集合,用来存储一个一个的对象

  • List接口:存储有序的、可重复的数据

    • ArrayList、LinkedList、Vector
  • Set接口:存储无序的、不可重复的数据

    • HashSet、LinkedHashSet、TreeSet

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

1.1 Collection接口常用方法

  • add(Object obj),addAll(Collection coll),size(),isEmpty(),clear();
  • contains(Object obj),containsAll(Collection coll),remove(Object obj),removeAll(Collection coll),retainsAll(Collection coll),equals(Objiect obj)
  • hasCode(),toArryay(),iterator();

1.2 Collection集合与数组间的转换

  • 集合————>数组:toArray()
public class Test {
    public static void main(String[] args) {
         Collection<Integer> coll = new ArrayList<>();
         coll.add(12);
         coll.add(123);
         coll.add(565);
Object[]arr=coll.toArray();
for(int i=0;i<arr.length;i++){
	System.out.println(arr[i]);
	}
}
  • 数组————>集合:调用Arrays类的静态方法asList()
public class Test2 {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("Aa", "AA", "Bbb");
        System.out.println(list);

        //雷区
        //Arrays.asList源码:传入一个变长泛型参数(注意泛型!),返回一个List集合,在Java中,泛型要求包容的是对象类型,而基本数据类型在Java中不属于对象,但是在示例代码中传入一个int[]类型的数组,程序并没有报错,是因为int[]是一个数组对象,示例代码把int类型的数组作为泛型传入,所以代码没有报错。
        List arr1= Arrays.asList(new int[]{123, 456});
        System.out.println(arr1.size());//1
		//所以使用Arrays.asList时,如果传入数组类型为基本数据类型,就使用对应的包装类作为入参:
        List arr2= Arrays.asList(new Integer[]{123, 456});
        System.out.println(arr2.size());//2
    }


}

1.3 遍历Colliction俩种方式

①使用迭代器Iterator

**GOF给迭代器模式的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。迭代器模式,就是为容器而生。**类似于“公交车上的售票员、”火车上的乘务员“、”空姐“

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R4vS7IIK-1657550642664)(C:\Users\永不遗憾&象牙塔\AppData\Roaming\Typora\typora-user-images\image-20220709104328004.png)]

  • Itrator仅用于遍历集合,Iterator本身并不提供承装对象的能力。如果需要创建Iterator对象,则必须有一个被迭代的集合。

  • 集合对象每次调用Iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。

public class Test{
    public static void main(String[] args) {
         Collection<Integer> coll = new ArrayList<>();
         coll.add(12);
         coll.add(123);
         coll.add(565);
         Iterator it = coll.iterator();
        //hasNext();判断是否还有下一个元素
         while (it.hasNext()) {
             //next():①指针下移②将下移以后集合位置上的元素返回
             System.out.println(it.next());
         }
    }
}
remove()的使用:
  • 测试Iterator中的remove()

  • 如果还未调用next()或在上次调用next方法之后已经调用了remove方法,再调用remove都会报IllegalStaeException.

  • 迭代器内部定义了remove(),可以在遍历时,删除集合中的元素,此方法不同于集合直接调用remove()

public class Test {
    public static void main(String[] args) {
         Collection coll = new ArrayList();
         coll.add(12);
         coll.add(123);
         coll.add(565);
       coll.add(new Person("TOM",12));
       coll.add(new String("Tom"));
         Iterator it = coll.iterator();
        while (it.hasNext()) {
           Object o = it.next();
          if (o.equals(12)) {
              it.remove();
           }

        }
        it=coll.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
         }
    }
②foreach循环(或增强for循环)
  • 内部仍调用了迭代器
  • for(集合元素的类型 局部变量 :集合对象)

遍历集合

public class Test{
    public static void main(String[] args) {
         Collection<Integer> coll = new ArrayList<>();
         coll.add(12);
         coll.add(123);
         coll.add(565);
        for (Integer integer : coll) {
            System.out.println(integer);
        }

    }
}

遍历数组

public void test(){
    int []arr=new int[]{1,2,3,4,5,6};
    //for(数组元素类型 局部变量:数组对象)
    for(int i:arr){
        System.out.println(i);
    }
}

二、Collection子接口List接口

2.1 存储特点:

  • Collection接口:单列集合,用来存储一个一个的对象
    • List接口:存储有序的、可重复的数据。——>“动态”数组,替换原来的数组
      • ArrayList:作为Lsit接口的主要实现类:线程不安全的,效率高;底层使用Objiect[]elementData存储
      • LinkedList:对于频繁的插入操作、删除操作,使用此类效率比ArrayList高:底层使用双向链表存储
      • Vector:作为List接口的古老实现类;线程是安全的,效率低:底层使用Object[]elementData存储
    • 添加的对象,所在的类要重写equals()方法

2.2 常用方法

  • 增: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循环

​ ③普通的循环

2.3源码分析

2.3.1 ArrayList的源码分析
jdk 7 情况下

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)

jdk 8中ArrayList的变化

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

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

​ …

​ 后续的添加和扩容操作与jdk7无异

小结
  • jdk7中的ArrayList的对象的创建类似于单例的饿汉式,而jdk8中的ArrayList的对象创建类似于单例懒汉式,延迟了数组创建节省内存
2.4 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;
        this.prev=prev;
    }
}
2.5 Vector的源码分析
  • jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组。

  • 在扩容方面,默认扩容为元凯的数组长度的2倍

2.6 作业(面试题)

ArrayList、LinkedList、Vector者的异同?

  • 相同点:三个类都实现了List接口,存储数据的特点相同:存储有序的、可重复的数据

  • 不同点:特点,数据结构,源码分析(见上 )

练习:在List内去除重复数字值,要求尽量简单

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> Listy = new ArrayList<>();
        Listy.add(1);
        Listy.add(2);
        Listy.add(2);
        Listy.add(2);
        Listy.add(5);
        Listy.add(6);
        List list = dupliicateList(Listy);
        for (Object o : list) {
            System.out.println(o);
        }


    }

    private static List dupliicateList(List list) {
        HashSet <Integer>hashSet = new HashSet();
        hashSet.addAll(list);
        return new ArrayList(hashSet);
    }

三、Collection子接口Set接口

3.1 存储特点

  • 无序的,不可重复的

  • 以HashSet为例说明:

    • 无序性:不等于随机性。存储的数据在底层数组中并非照数组索引的顺序添加,而是根据数据的哈希值决定
    • 不可重复性:保证添加的元素equals()判断时,不能返回true,即:相同的元素只能添加一个
  • Collection接口:单列集合,用来存储一个一个的对象

    • Set接口:存储无序的、不可重复的数据
      • HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值
      • LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以照添加的顺序遍历
      • TreeSet:可以照添加对象的指定属性,进行排序。

3.2 常用方法

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

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

  • 要求:重写的hashCode()和equals()尽可能保持一致性:相等的对象的散列码;重写两个方法的小技巧:对象中用作equals()方法比较的Field,都应该用来计算hashCode

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

  • 定制排序中,比较俩个对象是否相同的标准为:compare()返回,不再时equals().
    使用说明

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

  • 俩种排序方式:自然排序(实现Comparable接口)和定制排序(Comparator)

    自然排序
public class Test {
    public static void main(String[] args) {
        TreeSet<Person> set = new TreeSet<>();
        set.add(new Person("WangChao",31));
        set.add(new Person("Lisi",14));
        set.add(new Person("ZAHNG三",16));
         set.add(new Person("王五",17));
         Iterator<Person> it = set.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
           }

        }
         }
public class Person implements Comparable <Person>{
    int age;
    String name;
    public Person(){

    }
    @Override
    public String toString() {
        return "姓名"+this.name+
                "年龄"+this.age;
    }

    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    @Override
    public int compareTo(Person o) {
        return -(this.age - o.age);//降序
        //this.age - o.age 升序
    }
}
定制排序
public class Test2 {
    public static void main(String[] args) {
        TreeSet<Person> set = new TreeSet<Person>(new Comparator<Person>(){
            @Override
            public int compare(Person p1, Person p2) {
                int num = p1.getAge() - p2.getAge();
                int num2 = num == 0 ? p1.getName().compareTo(p2.getName()) : num;
                return num2;

            }


        });
        set.add(new Person("WangChao",31));
        set.add(new Person("Lisi",14));
        set.add(new Person("ZAHNG三",16));
        set.add(new Person("王五",17));
        for (Person p : set) {
            System.out.println(p);
        }
    }
    }

3.2.3 HashSet练习题
public class Test2 {
    public static void main(String[] args) {
        HashSet<Person> set = new HashSet<>();
        Person p1 = new Person(1001, "AA");
        Person p2 = new Person(1002, "BB");
        set.add(p1);
        set.add(p2);

        p1.name = "CC";
        set.remove(p1);
        System.out.println(set);
        set.add(new Person(1001,"CC"));
        System.out.println(set);
        set.add(new Person(1001,"AA"));
        System.out.println(set);
    }
}
/*[1002,BB, 1001,CC]
[1002,BB, 1001,CC, 1001,CC]
[1002,BB, 1001,CC, 1001,CC, 1001,AA]*/


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值