Collection集合

集合

1. 概念:

为了对多个对象进行操作,Java提供了集合类。

1.1 数组和集合的区别:

长度不同:数组是固定长度,集合是不固定长度。

内容不同:数组存储的数据类型相同,集合可以存储不同数据类型。

类型不同:数组可以存储基本数据类型和引用数据类型,集合只能存储引用数据类型。

1.2 集合的特点:

集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。

1.3 集合继承体系:

Collection:List,Set

List:ArrayList,Vector,LinkedList

Set:HashSet,TreeSet

2. collection

2.1 概述:

collection是集合层次中的根接口。集合表示一组对象的容器,这些对象有重复的,有不重复的,有有序的,有无无序的。

2.2 collection中的方法:

1. 添加方法:

   public boolean add(Object o):给集合添加元素

   public boolean addAll(Collection c):将一个集合添加到另一个集合当中

2. 删除出方法:

   public void clear():从该集合中删除所有元素

   public boolean remove(Object o):从该集合中删除指定元素

   public boolean removeAll(collection<?> c):从该集合中删除指定集合的元素

3. 判断方法:

   public boolean contains(Object o):判断该集合是否含有指定元素

   public boolean containsAll(Collection<?> c):判断该集合是否含有指定集合所有元素

   public boolean isEmpty():判断集合是否为空

4. 获取元素方法:

   public Iterator<E> iterator():通过迭代器来获取元素

   public Object[] toArray():返回包含此集合所有元素的数组

   public boolean retainAll(Collection c):求两个集合交集

5. 获取长度方法:

   int size():获取集合长度
/*
	普通方法使用
*/
public static void main(String[] args) {
        //创建集合对象
        Collection c = new ArrayList();

        //添加元素
        c.add("Hello");
        c.add("乐乐");
        c.add("java");
        System.out.println("c:"+c);//说明重写了toString()方法

        //删除元素
        //c.clear();//删除所有元素
        c.remove("Hello");//删除指定元素
        System.out.println("remove:"+c.remove("乐乐"));//删除存在的元素返回true
        System.out.println("remove:"+c.remove("啦啦啦"));//删不除存在的元素返回false
        System.out.println("c:"+c);

        //判断
        System.out.println("contains:"+c.contains("java"));//集合中存在该元素返回true
        System.out.println("contains:"+c.contains("乐乐"));//集合中不存在该元素返回false
        System.out.println("isEmpty:"+c.isEmpty());//集合为空返回true

        //获取集合长度
        System.out.println("size:"+c.size());
    }
/*
	集合与集合之间方法的使用
*/

public static void main(String[] args) {
        //创建集合 多态
        Collection c1 = new ArrayList();
        Collection c2 = new ArrayList();

        //添加元素
        c1.add("a1");
        c1.add("a2");
        c1.add("a3");
        c2.add("b1");
        c2.add("b2");
        c2.add("b3");
        c2.add("a1");
        System.out.println("c1:"+c1);
        System.out.println("c2:"+c2);

        //addAll(Collection c):将指定集合中所有元素添加到该集合中
        c1.addAll(c2);
        System.out.println("c1:"+c1);

        //removeAll(Collection c):删除该集合中指定集合的元素
        c1.removeAll(c2);
        System.out.println("c1:"+c1);

        //containsALL(Collection c):判断该集合是否含有指定集合的所有元素
        System.out.println(c1.containsAll(c2));//全包含指定集合返回true
        //c1.addAll(c2);
        //System.out.println(c1.containsAll(c2));

        //retainAll(Collection c):求交集
        //如果调用者集合元素
        c1.add("b1");
        System.out.println(c1.retainAll(c2));//该集合发生改变返回true
        System.out.println("c1:"+c1);
    }

3.迭代器

Iterator iterator():专门遍历集合的迭代器

3.1 Iterator接口中的方法:

public Object next();返回集合中的下一个元素

public Object hasNext():如果next()返回一个元素而不是一个异常,则返回true

注意:NoSuchElementException:不存在这个元素异常

3.2 集合使用步骤

  1. 创建集合对象
  2. 创建集合元素
  3. 将元素添加到集合中
  4. 遍历集合
/*
	遍历学生对象集合
*/
public static void main(String[] args) {
        Collection c = new ArrayList();

        Student s1 = new Student("王宝强",25);
        Student s2 = new Student("张卓帆",19);
        Student s3 = new Student("张三",22);

        c.add(s1);
        c.add(s2);
        c.add(s3);

        //声明一个迭代器
        Iterator i = c.iterator();
        //判断有没有下一个元素,并接收它
        while(i.hasNext()){
            Object o = i.next();
            Student s = (Student)o;//Student s = (Student)i.next();
            System.out.println(s.getName()+"----"+s.getAge());
        }
    }

4. List

4.1 概述:

有序集合:插入元素顺序和取出元素顺序一致

允许有重复元素

4.2 List中的特有方法

public void add(int index,Object element):向指定位置添加元素

public Object remove(int index):移除指定位置元素并返回该元素

public Object get(int index):获取指定位置元素

public Object set(int index,Object element):替换指定位置元素,并返回原来的元素
public static void main(String[] args) {
        List l = new ArrayList();
        l.add("hello");
        l.add("love");
        l.add("away");
        l.add("hello");
        System.out.println(l);

        //添加元素
        l.add(4,"fall");//四个元素:0-4,否则数组下标越界
        //l.add(5,"fall") 数组下标越界
        System.out.println(l);

        //删除元素
        l.remove(2);
        //System.out.println("remove:"+l.remove(2));删除哪个元素,并返回该元素
        System.out.println(l);

        //获取元素
        System.out.println("get:"+l.get(2));

        //替换元素
        System.out.println("set:"+l.set(1,"you"));
        System.out.println(l);
    }
List特有的迭代器:
public ListIterator ListIterator():迭代器

public Object previous():返回集合中上一个元素,并且光标前移

public boolean hasPrevious():返回true如果遍历反向别表,列表迭代器有多个元素

注意:当我们光标没有正向遍历的时候,它就在其实位置,这时候如果你要逆向输出,则不会有输出结果

public static void main(String[] args) {
        List l = new ArrayList();
        l.add("hello");
        l.add("love");
        l.add("getAway");

//        for (int i = 0;i<l.size();i++){
//            System.out.println(l.get(i));
//        }
        ListIterator li = l.listIterator();
        while(li.hasNext()){
            String s = (String)li.next();
            System.out.println(s);
        }

        System.out.println("===============");

        //逆序输出
        while(li.hasPrevious()){
            String s = (String)li.previous();
            System.out.println(s);
        }
    }

练习:想要在集合hello,world,java中判断如果world存在就添加i love

/**
 *   注意:ConcurrentModificationException:并发修改异常
 *        当不允许这样的修改时,可以通过检测到对象的并发修改的方法来抛出此异常
 *   为什么会出现这种异常?
 *      首先我们知道,迭代器是依赖集合存在的,我们的迭代器已经在刚开始就固定了
 *      这时候,我们通过迭代器来遍历集合,而集合中突然添加了一个元素,我们的迭代器并不知道
 *      所以就会发生并发修改异常
 *    如何解决这种问题:
 *       1. 迭代器迭代,迭代器修改
 *            元素插入我们想要插入的位置
 *       2. 集合遍历,集合修改
 *            元素插入到集合的最后
 *
 */
    public static void main(String[] args) {
        List l = new ArrayList();
        l.add("hello");
        l.add("world");
        l.add("java");

        //通过迭代器
        ListIterator li = l.listIterator();
        while (li.hasNext()){
            String s = (String)li.next();
            if (s.equals("world")){
                // l.add(2,"i love");并发修改异常  ConcurrentModificationException
                li.add("love");
            }
        }

        //通过集合,使用for循环
        for(int i = 0;i<l.size();i++){
            String s = (String) l.get(i);
            if (s.equals("world")){
                l.add("hate");
            }
            System.out.println(s);
        }
        System.out.println(l);
    }
}

5. List的子类

ArrayList:

​ 底层数据结构是数组,所以查询快,增删慢。

​ 又因为线程不同步,所以效率高。

Vector:

​ 底层数据结构是数组,所以查询快,增删慢。

​ 又因为线程同步,所以效率低。

LinkedList:

​ 底层数据结构是链表,所以查询慢,增删快。

​ 又因为线程不同步,所以效率高。

我们到怎么样使用这些集合呢?

  1. 首先考虑线程是否安全:

    如果需要线程安全,选择Vector

  2. 看业务需求:

    如果对查询有要求,选择ArrayList

    如果对增删有要求,选择LinkedList

  3. 如果我们啥都不知道,就选择ArrayList

5.1 Vector中特有方法:

public void addElement(Object o):添加元素

public Object elementAt(int index):按照索引获取元素

public Eumeration elements():其实是一个迭代器
       public boolean hasMoreElements():判断是否有下一个元素
       public Object nextElement();返回下一个元素

vector练习:

public static void main(String[] args) {
        Vector v = new Vector();

        //添加元素
        v.addElement("hello");
        v.addElement("world");
        v.addElement("java");

        //获取元素
        for(int i = 0;i<v.size();i++){
            String s = (String)v.elementAt(i);
            System.out.println(s);
        }
        System.out.println("==================");
        //迭代器
        Enumeration e = v.elements();
        while(e.hasMoreElements()){
            String s = (String)e.nextElement();
            System.out.println(s);
        }
}

5.2 LinkedList的特有方法:

public void addFirst(Object o) 及 addLast(Object o)
public Object getFirst() 及 getLast()
public Object removeFirst() 及 removeLast()

练习:

 public static void main(String[] args) {
        LinkedList l = new LinkedList();
        l.add("hello");
        l.add("world");
        l.add("java");

        //添加元素
        l.addFirst("love");
        l.addLast("YOU");
        System.out.println(l);

        //删除元素
        l.removeFirst();
        l.removeLast();
        System.out.println(l);

        //获取元素
        String s1 = (String)l.getFirst();
        String s2 = (String)l.getLast();
        System.out.println(s1);
        System.out.println(s2);

    }

6.泛型

6.1 泛型的概述

由于添加元素的类型不确定,我们可以添加任意类型的元素,那么在遍历的时候可能就会出现问题。

我们之前学习过数组,就可以声明一种类型,使得在添加元素时,数据类型不匹配的情况就会出现异常。

那么集合中有没有这样的方法呢?从而引出了:泛型

  • 泛型的概念:泛型是一种特殊的类型,可以理解为参数化类型,也就是可以把类型像参数一样传递。

  • 泛型的用途:一般多用于集合。

  • 泛型的格式:<泛型类型>

  • 泛型的好处:1.提高了程序的安全性,将原本运行时期的错误提前在编译阶

    ​ 段就暴露出来

​ 2.省去了类型的强制转换的麻烦

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

public class TestArrayListDemo03 {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<String>();
        arrayList.add("dll");
        arrayList.add("love");
        arrayList.add("yx");
        //arrayList.add(5);
        Iterator<String> iterator = arrayList.iterator();
        while (iterator.hasNext()){
            //String s = (String)iterator.next();
            String s = iterator.next();
            System.out.println(s);
        }
    }
}

6.2 泛型的应用

  • 泛型类

    把泛型定义在类上
    public class 类名 <泛型类型1,……>
    泛型类型必须是引用类型
    
    /**
     * 泛型类:
     *      概述:把泛型定义在类上
     *      格式:public class 类名 <泛型类型1,……> 这里泛型类型可以有多个
     *      注意:泛型类型必须是引用数据类型,而且要符合我们的命名规范
     */
    public class TestFanxingDemo05 {
        public static void main(String[] args) {
            MyFanxing<String> myFanxing = new MyFanxing<String>();
            myFanxing.setObj("金城武");
            String s1 = myFanxing.getObj();
            myFanxing.setObj("21");
            String s2 = myFanxing.getObj();
            System.out.println(s1+s2);
    
            MyFanxing<Integer> myFanxing1 = new MyFanxing<Integer>();
            myFanxing1.setObj(15);
            Integer obj = myFanxing1.getObj();
            System.out.println(obj);
        }
    
    }
    class MyFanxing<T>{
        private T obj;
        public T getObj(){
            return obj;
        }
        public void setObj(T obj){
            this.obj = obj;
        }
    }
    
    
  • 泛型方法

    把泛型定义在方法上
    public <泛型类型> 返回值类型 方法名(泛型类型)
    
    /**
     * 泛型方法:将泛型定义在方法上
     * 格式:public <泛型类型> 返回值类型 方法名(泛型类型)
     */
    public class TestFanxingDemo07 {
        public static void main(String[] args) {
            MyFanxing3 myFanxing3 = new MyFanxing3();
            myFanxing3.show("dll");
            myFanxing3.show(21);
            myFanxing3.show(true);
        }
    }
    class MyFanxing3{
        public <T> void show(T t){
            System.out.println(t);
        }
    }
    
    
    
  • 泛型接口

    把泛型定义在接口上
    public interface 接口名 <泛型类型>
    
    /**
     *  泛型接口
     *  概述:将泛型定义在接口上
     *  格式:public interface 接口名 <泛型类型>
     */
    public class TestFanxingDemo08 {
        public static void main(String[] args) {
            //方法1:
            MyFanxing4<String> m1 = new RealizeMyFanxing4();
            m1.show("dll");
    
            //方法2
            MyFanxing4 <String> m2 = new RealizeMyFanxing5<String>();
            m2.show("yx");
            MyFanxing4<Integer> m3 = new RealizeMyFanxing5<Integer>();
            m3.show(21);
            MyFanxing4<Boolean> m4 = new RealizeMyFanxing5<Boolean>();
            m4.show(true);
    
        }
    }
    interface MyFanxing4<T>{
        public abstract void show(T t);
    }
    //在使用泛型接口时,需要知道到底什么明确使用泛型类型
    //1.在实现类的时候就已经明确了泛型类型
    //2.在使用的时候才知道泛型类型到底是什么
    class RealizeMyFanxing4 implements MyFanxing4 <String>{
        @Override
        public void show(String s) {
            System.out.println(s);
        }
    }
    class RealizeMyFanxing5 <T> implements MyFanxing4<T>{
        @Override
        public void show(T t) {
            System.out.println(t);
        }
    }
    

6.3 泛型的高级应用

泛型通配符<?>
	任意类型,如果没有明确,那么就是Object以及任意类型的Java类
<? extends E>
	向上限定,只能是E及其子类
<? super E>
	向下限定,只能是E及其父类

7. 增强for

  • 概述:简化数组和collection的遍历

  • 格式:

    for(元素数据类型 变量名:数组或者Collection集合){
    			方法体
      }
    
    import java.util.ArrayList;
    
    /**
     * 增强for:
     *      概述:简化数组或者集合的遍历
     *      格式:for(元素数据类型 变量名:集合或者数组对象){
     *                  通过变量名来使用元素
     *      }
     *      好处:简化了遍历
     *      弊端:我们在使用它之前,需要判断遍历的数组或者集合是否为空,因为它会发生空指针异常
     *      注意:我们的增强for其实就是用来代替迭代器的
     */
    public class TestForDemo01 {
        public static void main(String[] args) {
            int[] arr = {1,2,3,4,5};
            for (int x:arr){
                System.out.println(x);
            }
            System.out.println("===========");
    
            ArrayList<String> arrayList = new ArrayList<String>();
            arrayList.add("hello");
            arrayList.add("world");
            arrayList.add("java");
            for (String s:arrayList){
                System.out.println(s);
            }
    
            //需要先判断需要遍历的数组是否为空
            arrayList = null;
            if (arrayList!=null){
                for (String s:arrayList){
                    System.out.println(s);
                }
            }
        }
    }
    
    

8. Set

8.1 set集合

import java.util.HashSet;
import java.util.Set;

/**
 * Set接口:
 *      概述:不包含重复元素的集合,它是无序的(存入顺序和取出顺序不一致),相对于List集合来说的。
 *      并且List集合是有序的(指存入数据顺序和取出数据顺序一致)
 *
 */
public class TestSetDemo01 {
    public static void main(String[] args) {
        Set<String> s = new HashSet<>();

        s.add("dll");
        s.add("love");
        s.add("yx");
        s.add("yx");

        System.out.println(s);
    }
}

8.2 HashSet集合

import java.util.HashSet;

/**
 * HashSet:
 *      概述:一个实现set接口的类,它不能保证迭代顺序,特别是它不保证在一段时间内的迭代顺序。
 *
 *      HashSet是如何保证元素的唯一性:
 *             1.底层数据结构是哈希表
 *             2.哈希表底层依赖了两个方法
 *                  首先会判断hashCode()是否相等,
 *                  如果不相等就说明两元素不一样,直接添加;
 *                  如果相等,就会继续判断equals()方法,
 *                  如果equals方法返回false,则添加元素。
 *
 */
public class TestHashSetDemo02 {
    public static void main(String[] args) {
        HashSet<String> hs = new HashSet<String>();

        hs.add("hello");
        hs.add("dll");
        hs.add("lyy");
        hs.add("lyy");

        for (String s:hs){
            System.out.println(s);
        }

        //如果元素相等,则hashCode值相等,保证元素的唯一性!
        System.out.println("lyy".hashCode());
        System.out.println("lyy".hashCode());
    }
}

8.3 LinkedHashSet

import java.util.LinkedHashSet;

/**
 * LinkedHashSet:
 *      概述:它是一个有序的切元素唯一的集合
 *      它的底层是链表和哈希表
 *      唯一性由哈希表保证
 *      有序性由链表保证
 */
public class TestLinkedHashSetDemo04 {
    public static void main(String[] args) {
        LinkedHashSet<String> l = new LinkedHashSet<String>();

        l.add("dll");
        l.add("wrh");
        l.add("wrh");
        l.add("yx");

        for (String s:l){
            System.out.println(s);
        }
    }
}

8.4 TreeSet

import java.util.TreeSet;

/**
 * TreeSet:
 *      概述:基于TreeMap的实现,使用元素的自然顺序或者比较器排序。这取决于我们选取的构造方法
 *      特点: 元素唯一,且根据选取的构造方法来给元素排序
 *              通过刚才查看源码,发现它十几场是实现了自然排序结构Comparable,并且调用Comparable
 *
 *       红黑树存取原理:
 *          第一个元素作为红黑树的节点,后面的元素依次和之前的元素比较,如果小了往左放,如果大了往右放,如果相等就不放
 *          
 */
public class TestTreeSetDemo05 {
    public static void main(String[] args) {
        //因为我们使用的是无参构造,所以这里是按照自然顺序排序
        TreeSet<Integer> t = new TreeSet<Integer>();

        t.add(20);
        t.add(18);
        t.add(23);
        t.add(22);
        t.add(17);
        t.add(24);
        t.add(19);
        t.add(18);
        t.add(24);

        for (Integer i:t){
            System.out.println(i);
        }

    }
}

9. 总结

Collection:

  • List:有序切可以重复

    • ArrayList

      底层数据结构是数组,查询快,增删慢,线程不安全,效率高

    • Vector

      底层数据结构是数组,查询快,增删慢,线程安全,效率低

    • LinkedList

      底层数据结构是链表,查询慢,增删快,线程不安全,效率高

  • Set

    • HashSet:无序切唯一

      底层数据结构是哈希表,它的底层依赖hashCode和equals方法来实现元素唯一

      • LinkedHashSet:有序切唯一

        底层数据结构是哈希表和链表,哈希表保证元素唯一性,链表保证元素有序

    • TreeSet:有序切唯一

      底层数据结构是红黑树,它的排序由构造方法决定,一种是自然排序,一种是比较器排序

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值