Collection体系集合之List

1. Collection父接口

特点:代表一组类型的对象,是无序、无下标的。

简单的方法介绍:

  1. boolean add()//添加一个元素
  2. boolean addAll()//将指定集合的元素全部添加到目标集合
  3. void clear()//移除所有的元素
  4. boolean contains()//判断是否包含
  5. boolean equals(Object o)//判断是否相等
  6. Iterator iterator()//迭代器
  7. boolean remove()//移除元素
  8. boolean retain()//保留某某某元素
  9. int size()
  10. toArray() //数组相关

集合一般都是围绕增删查改,遍历展开的。

集合遍历方法及介绍

//遍历1.利用for进行遍历
        for (Object object : collection){
            String str = (String)object;
            System.out.println(str);
            //collection.remove(object); 会出现并发修改异常,利用for不能删除元素
        }

        //遍历2.使用迭代器
        //迭代器利用三个统一的方法进行遍历所有集合hasNext()、next()、remove()
        Iterator it = collection.iterator();
        while (it.hasNext()){//是否有下一个元素
            Object o = it.next();//返回元素
            System.out.println(o);
            //it.remove(); //删除元素
        }

        //注意事项:使用迭代器或者是for进行遍历的时候,不能使用集合的删除方法进行元素删除。
        //只能使用迭代器进行删除,否则会出现并发修改异常(ConcurrentModificationException)

2. 接口List

2.1 List总述

特点:有序,有下表,元素的值是可以重复的

方法介绍:(介绍List有但是Collection没有的)

  1. E get()//返回指定位置元素
  2. int indexOf(Object o)//返回第一次出现某元素的索引,没有就返回-1
  3. listIterator//功能比Iterator更加强大
  4. void set(int index, E element) //修改
  5. List subList(int from, int to)//截取列表

List遍历方式如下

//List遍历
        //1.使用for,还是不能利用集合本身的方法进行删除,不能添加,可以修改
        //2.使用Iterator
        //3.使用ListIterator(可以删除、添加、逆向遍历、修改)
        ListIterator lit = list.listIterator();
        while (lit.hasNext()){

            System.out.println(lit.nextIndex()+" "+lit.next());
        }
        //逆向
        while (lit.hasPrevious()){

            System.out.println(lit.previousIndex()+" "+lit.previous());
        }
        //4.利用下角标
        for (int i = 0;i < list.size(); i++){
            System.out.println(list.get(i));
        }

List删除方法介绍

List<Student> list = new ArrayList<Student>();
        Student stu1 = new Student(1,"11",12);
        Student stu2 = new Student(2,"22",13);
        Student stu3 = new Student(3,"33",14);

        list.add(stu1);
        list.add(stu2);
        list.add(stu3);

        System.out.println(list.toString());

        //删除元素 方法1
        list.remove(stu1); //可以删除元素
        System.out.println(list.toString());

        //删除元素  方法2
        list.remove(new Student(2,"22",13));
        System.out.println(list.toString());
        //发现运行之后并没有删除

上述代码运行结果如图所示

java 集合能做全局变量么 java如何定义全局list_Pig


可以看到第二种方式并没有删除成功,这是由于默认的equals函数比较的是两个对象的地址,新建的(2,22,13)的地址与原本的地址肯定不同所以是删除不掉的。

java 集合能做全局变量么 java如何定义全局list_Pig_02


这个时候,如果想利用这种方式进行删除,只需要重写equals方法,使其比较的是“值”,也就是说我要删除的是和(2,22,13)这个对象值相同的元素。

在Student里面重写equals

@Override
    public boolean equals(Object o) {

        if (o == null)
            return false;

        if(this == o)
            return true;

        if(o instanceof Student){
            Student stu = (Student)o;
            if(this.ID == stu.ID && this.name.equals(stu.name) && this.age == stu.age){
                return  true;
            }
        }
        return false;

    }

如此,运行结果如下

java 集合能做全局变量么 java如何定义全局list_java_03


可以发现成功删除了

注:同样的理论可以,还可以用在contains里面这种。。。就不进行赘述了。

2.2 ArrayList

内部使用数组实现,查询元素较为高效,删除和增加元素较慢。

ArrayList的add函数源码介绍

  1. ArrayList的无参构造函数会实现创建一个长度为0的数组。
  2. 在添加第一个元素的时候,这个数组的长度会更新为10,并将第一个要添加的元素的放在第0位置。
  3. 之后当添加的元素数量超出当前数组的容量时,数组的长度会变为其原本长度的1.5倍。

remove介绍(此处的remove是利用下标进行元素移除的remove)

主要有两步

  1. 计算要移动的元素个数
  2. 利用了System.arraycopy()这个函数

上述的源码如下所示:

int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null;

其中 elementData是存储元素的数组,index为当前移除元素的下标。

2.3 LinkedList

特点:删除和增加的效率要高,查询的效率低
与ArrayList的不同之处在于,ArrayList是使用数组,而LinkedList使用的是双向链表结构
具体的使用方法与ArrayList一样,就不再进行赘述了。

2.4 Vector

Vector的方法中多了一个枚举方法,因此其遍历方法一共有五种:

  1. 增强for
  2. Iterator
  3. ListIterator
  4. for
  5. 枚举

枚举方法的代码如下所示:

Enumeration en = vector.elements();
        while (en.hasMoreElements()){
            en.nextElement();
        }

Vector与ArrayList的实现方法比较

Vector

ArrayList

数组实现

数组实现

线程安全

线程不安全

效率较低

效率较高

2.5栈与队列
  1. 栈:Stack类继承自Vector接口,主要两种方法push(入栈)、pop(出栈)。
  2. 队列:Queue接口,继承自Collection接口,主要方法两种offer(入队)、poll(出队)。

上述两种接口,LinkedList也都有所实现,二者的简单使用代码如下所示。

//Stack stack = new Stack();
        LinkedList stack = new LinkedList();
        stack.push("wo");
        stack.push("ni");
        stack.push("ta");

        int count = stack.size();
        for(int i = 0;i < count; i++){
            Object o = stack.pop();
            System.out.println(o);
        }

        Queue queue = new LinkedList();
        queue.offer("wo");
        queue.offer("ni");
        queue.offer("ta");

        int count1 = queue.size();
        for(int i = 0; i < count;i++){
            System.out.println(queue.poll());
        }
        System.out.println(queue.size());

注:此处的pop、poll都是直接出栈、出队。

3. 集合与泛型

3.1 简单的例子

泛型,集合都是使用泛型的,例子:

ArrayList<Pig> pigs = new ArrayList<Pig>();

        Pig pig1 = new Pig(1,"xiaomi");
        Pig pig2 = new Pig(2,"dami");

        pigs.add(pig1);
        pigs.add(pig2);

        Iterator<Pig> it = pigs.iterator();
        while (it.hasNext()){
            System.out.println(it.next().toString());
        }

都加上类型,更加规范。不加类型的时候,默认是Object

3.2 集合与泛型与“?”
public static void main(String[] args) {

        ArrayList<Pig> pigs = new ArrayList<Pig>();

        Pig pig1 = new Pig(1,"xiaomi");
        Pig pig2 = new Pig(2,"dami");

        pigs.add(pig1);
        pigs.add(pig2);

        ArrayList<String> list = new ArrayList<String>();
        list.add("ni");
        list.add("wo");
        list.add("ta");
        
    }

上述pigs和list是否可以通过一个函数进行遍历。如何实现?
方法如下:

public static void main(String[] args) {

        ArrayList<Pig> pigs = new ArrayList<Pig>();

        Pig pig1 = new Pig(1,"xiaomi");
        Pig pig2 = new Pig(2,"dami");

        pigs.add(pig1);
        pigs.add(pig2);

        ArrayList<String> list = new ArrayList<String>();
        list.add("ni");
        list.add("wo");
        list.add("ta");

        show(pigs);
        show(list);

    }

    public static void show(ArrayList<?> list){

        Iterator<?> it = list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
    }

注:此处的“?”表示任何类型。

运行结果如下:

java 集合能做全局变量么 java如何定义全局list_数组_04


此处的"?"在使用的时候,还可以规定其上限以及下限。

  1. 泛型的上限,? extend Pig ,"?"只能是pig以及Pig的子类
  2. 泛型的下限,? super Pig ,"?"只能是Pig以及Pig的父类
    具体的使用代码如下:
public static void show1(ArrayList<? extends Pig> list){
        Iterator<?> it = list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
    }

主函数里的调用代码如下:

ArrayList<PetPig> petpigs = new ArrayList<PetPig>();
        petpigs.add(new PetPig(12,"dahuang"));
        show1(petpigs);

4. 集合的工具类Collections

常用的方法,直接上例子吧。
比较简单

public static void main(String[] args) {

        List<Integer> list = new ArrayList<Integer>();
        list.add(102);
        list.add(100);
        list.add(10);
        list.add(55);

        //排序
        System.out.println("排序之前"+list.toString());
        Collections.sort(list);
        System.out.println("排序之后"+list.toString());

        //二分查找
        int pos = Collections.binarySearch(list,100);
        System.out.println(pos);
        System.out.println(list.get(pos));

        //注意目标集合的大小要和原集合的大小要大于等于
        ArrayList<Integer> arrayList = new ArrayList<Integer>();
        for(int i = 0;i < list.size();i++ )arrayList.add(0);
        Collections.copy(arrayList,list);

        //反转
        Collections.reverse(list);
        System.out.println("反转之后的list"+ list.toString());

        //打乱顺序
        Collections.shuffle(list);
        System.out.println(list.toString());



    }

5. 集合与数组

集合与数组可以相互转换的。

  1. 数组转集合
//数组转集合
        //转完之后不能添加和删除元素,但是可以使用集合的方法
        String[] persons = {"ni","wo","ta"};
        List<String> list1 = Arrays.asList(persons);
  1. 集合转数组
//集合转数组
        //new String[0],是为了获取类型
        //如果new的数组的长度(String[0])小于或等于集合的长度,返回的数组的长度和集合一样(此时arr的长度为3)
        //如果new的数组的长度大于集合(String[10])的长度,则返回数组的长度的和指定的长度一致(此时arr的长度为10)
        String[] arr = list1.toArray(new String[0]);
        System.out.println(arr.length);

里面的注意事项,可以在自己的机器上跑一跑,就会很明确。