集合中的知识点

集合

数组长度固定,集合长度可变

若对象数据比较多,而且数据个数不固定时,使用集合存储。

一、Collection集合

是一个接口 ,保存单个数据

有两个主要子接口List和Set。

List 有ArrayList、LinkedList、Vector 三个主要实现类

Set有HashSet、LinkedHashSet 两个主要实现类

1.1Collection通用的方法

Collection有通用的方法,List和Set都可以使用。

public class Demo {
    public static void main(String[] args) {
        //使用多态创建多个Collection类型的子类
        //c1~c6 只能调用Collection接口里的方法
        Collection c1 = new ArrayList();//Collection是接口不能直接new对象
        Collection c2 = new LinkedList();
        c2.add("good");
        c2.add(13);
        c2.add("张三");
        Collection c3 = new Vector();
        Collection c4 = new HashSet();
        Collection c5 = new LinkedHashSet();
        Collection c6 = new TreeSet();

        c1.add(1);//添加元素
        c1.add(2);
        c1.add("hello");
        c1.remove(1);//删除元素
        c1.addAll(c2);//将一个Collection添加到另一个Collection里
        c1.removeAll(c2);//将一个Collection里的另一个Collection移除
        c1.clear();//清空
        c1.contains("hallo");//判断c1中有没有"hello"元素,返回结果为boolean类型
        c1.containsAll(c2);//判断c1中是否包含c2
        c1.isEmpty();//判断c1是不是空的
        c1.size();// 元素的个数
        Object[] objects = c1.toArray();//将c1转换为数组
        System.out.println(c1.toString());
    }
}
1.2迭代器

Iterator 接口用来遍历Collection。

package com.atguigu.collection;

import java.util.ArrayList;
import java.util.Collection;

public class IterDemo {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add("张三");
        c.add("李四");
        c.add("jack");
        c.add("rose");
        c.add("王五");
        c.add("tony");
        c.add("tom");
        c.add("jerry");
    }
}
1.2.1 遍历Collection的几种方式

1.通过获取迭代器iterator,调用hasNext()判断是否有下一个元素,使用next()获取元素。while循环

Iterator iterator = c.iterator();//获取到Collection对象的迭代器
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

2.增强for循环

  for (Object o : c) {
            System.out.println(o);
        }
1.3泛型

虽然Collection可以存储不同类型,但通常情况下也是存储同一类型。业务逻辑和从数据处理角度分析,方便操作数据。

使用泛型——>在定义Collection的时候,就规定元素的数据类型。将运行时的错误提前,在编译的时候暴露出来。

<> 泛型中规定的是一个对象,不能写基本数据类型,可以写基本包装类型Integer等。创建对象时泛型可以省略,但<>建议保留。泛型不支持多态。

public static void main(String[] args) {
        Collection<Integer> scores = new ArrayList<>();
        //Collection<Object> scores = new ArrayList<Integer>(); 泛型不支持多态
        scores.add(98);
        //scores.add("87");编译报错
        int sum = 0 ;
        //使用时,类型不再是Object类型,可以直接使用泛型声明的类型
        for (Integer score : scores) {
            sum+=score;
        }
    }

可以在类中自定义泛型,然后在别的类中调用

package com.atguigu.collection;

//<T>声明泛型,在整个类中都可以使用,可以作为参数也可以作为返回值
public class MyGeneric<T> {
    public void test(T t) {
        System.out.println(t);
    }

    public T demo() {
        return null;
    }

    //在泛型中还可以声明别的泛型<E>与<T>无关
    public <E> void foo(E e) {
        System.out.println(e);
    }
    //在泛型中还可以声明别的泛型<G> ,返回G类型数据
    public <G> G bar() {
        return null;
    }
}
package com.atguigu.collection;

public class MyGenericDemo {
    public static void main(String[] args) {
        MyGeneric<String> mg = new MyGeneric<>();
        //mg.test(2);报错,只能传入String类型的参数
        mg.test("hello");
        mg.demo();

        MyGeneric<Integer> mg1 = new MyGeneric<>();
        mg1.test(34);
        mg1.foo('a');//此时为Character类型
    }
}

泛型的通配符:? 使用时不能传入?因为无法存放数据。

通常?不会单独使用,会配合super以及extends规定泛型的上下限。

Collection<? extends Person>

表示需要的对象为Person类,或者它的子类

Collection<? super Person>

表示需要的对象是Person类,或者它的父类。

泛型通配符的使用场景:

在java.util包里还有一个Collections 工具类 通常用来快速操作LIst 的

<T extends Comparable<? super T>> void sort(List list)
将 Teacher 类型赋值给泛型,T还不能直接将 Teacher 赋值给 T,因为方法声明里要求 T 类型要实现 Comparable接口,并实现 CompareTo方法。Comparable接口也允许泛型,泛型的类型必须要是 Teacher类或者它的父类类型。

1.4 List接口

List接口继承自Collection接口, 所有Collection接口里的方法List创建出来的实例对象都可以调用,常见方法如add/ addAll/ remove/ removeAll/ clear/ isEmpty/ size。

Collection接口里没有get方法,不能获取到元素,因为Collection有两个子接口,List(有序)和Set(无序),所以不能通过序号编号等获取到指定元素。但是List里元素有序,可以通过序号获取到指定位置的元素,也可以调用set方法。

除了Collection中的两种遍历方法,List中还有一种for循环的遍历方式

package com.atguigu.list;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        List<String> l = new ArrayList<>();
        l.add("张三");
        l.add("李四");
        l.add("王五");
        l.add("赵六");
        l.add("托尼");
        l.add("汤姆");
        System.out.println(l.get(0));
        l.set(3,"小强");//将下标为3的元素替换为小强
        System.out.println(l);
        /*   遍历方法
        1.使用迭代器
        Iterator<String> iterator = l.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        2.增强for循环
        for (String s : l) {
            System.out.println(s);
        }
         */
        //List多一种遍历的方式,就是fori循环,通过下标来操作元素
        for (int i = 0; i < l.size(); i++) {
            System.out.println(l.get(i));
        }
    }
}

在List接口中,删除元素时要注意。若有相同的元素紧挨着就会出现删不干净的情况,需要倒着遍历删除!!

**注意:增强for循环不能删除和添加元素(不能修改数据的长度。**原因是因为在List的add和remove方法被调用以后,modCount变量都会自增。在迭代器的next方法里,会判断modCount和expectedModCount的值是否相等,如果不相等就会报错!

package com.atguigu.list;

import java.util.ArrayList;

public class ListDemo2 {
    //删除元素的注意事项
    public static void main(String[] args) {
        ArrayList<String> heroes = new ArrayList<>();
        heroes.add("钢铁侠");
        heroes.add("蜘蛛侠");
        heroes.add("雷神");
        heroes.add("蝙蝠侠");
        heroes.add("超人");
        heroes.add("闪电侠");
        heroes.add("雷神");
        heroes.add("雷神");
        heroes.add("海王");
       /* for (int i = 0; i < heroes.size(); i++) {
            if (heroes.get(i).equals("雷神")){
                //heroes.remove(i);
                heroes.remove("雷神");
                i--;//再重新看一次删除的那个位置的值,不然靠在一起的同样元素删不掉
            }
        }*/
       //删除满足条件的所有元素,需要倒着遍历
        for (int i = heroes.size() - 1; i >= 0; i--) {
            if (heroes.get(i).equals("雷神")) {
                heroes.remove(i);
            }
        }
        System.out.println(heroes);
        /*增强for循环不能删除和添加元素(不能修改数据的长度)
        原因是因为在List的add和remove方法被调用以后,modCount变量都会自增
        在迭代器的next方法里,会判断modCount和expectedModCount的值是否相等,如果不相等就会报错!
         */
        
    }
}
1.4.1 List的常用子类

ArrayList 实现了List接口,内部维护了一个数组,关于下标的方法都可以使用,例如 add、remove、set、indexOf等。

ArrayList 和LinkedList的区别:

最大的区别就在于数据结构不同:

1.ArrayList 内部维护了一个数组,查询速度较快,但是插入数据速度较慢。

2.LinkedList 内部是一个链表的数据结构,查询速度较慢,插入速度较快。

一、ArrayList源代码分析:

1.创建ArrayList的时候,会在内部维护一个空的数组。

2.当调用add方法的时候,才会给数组指定长度(懒加载)。

3.JDK7(包括)以后,都是懒加载,只要不添加元素,内部维护的就是一个长度为0 的空数组;

JDK6(包括)以前,上来就直接给内部的数组指定长度为10的空数组。

4.当数组的数据填满了以后,会扩展为原来数组长度的1.5倍。

当添加第11个元素的时候,minCapacity计算以后的结果为11

private void grow(int minCapacity) {  // minCapacity --> 11
        int oldCapacity = elementData.length;  // oldCapacity --> 10
        int newCapacity = oldCapacity + (oldCapacity >> 1);  // newCapacity = 10 + (10 >> 1) ==> 15
        if (newCapacity - minCapacity < 0)  // 15 - 11 < 0
            newCapacity = minCapacity;
        elementData = Arrays.copyOf(elementData, newCapacity);  // 把elementData原有的数据拷贝到 elementData,并将长度修改为15
    }

二、LinkedList源代码分析:

内部是维护了一个双向链表,Node为节点,Frist是链表第一个,Last为最后一个。一个Node中至少有三个数据,添加元素时不是直接放到链表中,而是封装一下变成Node对象,Node对象中保存三个数据,第一个为prev(上一个数据),第二个是添加的元素数据,第三个为next(下一个数据)。添加第一个数据时,First和Last都为空null,走完之后新建一个节点 在Last后面,成为新的最后一个。。。

1.5 Set接口

Set接口没有在Collection父接口的基础上新增方法。

Set的特点:

  1. Set里存储的数据是无序的

  2. Set里存储的数据都不允许重复。

    2.1 如何保证HashSet里的元素不重复。

    1)通过hashCode()方法来判断元素的哈希值是否一样。

    2)如果哈希值一样,再调用元素的equals 方法, 看equals的结果是否是true

    3)如果哈希值一样,equals的结果也是true,就会认为这两个元素是同一个元素,只会存入一个数据。

TreeSet注意事项:

  1. 存入的元素必须要实现Comparable接口
  2. TreeSet 会根据Comparable 接口里的 compareTo 方法的返回值对元素进行排序
  3. 如果compareTo方法的返回值是0,会认为是同一个元素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值