集合之Collection以及迭代器和比较器

集合

1. 集合的概念

  1. 集合是Java API所提供的一系列类,可以用于动态存放多个对象。–集合只能存对象

  2. 集合与数组的不同在于,集合是大小可变的序列,而且元素类型可以不受限定,只要是引用类型。(集合中不能放基本数据类型,但可以放基本数据类型的包装类)

  3. 集合类全部支持泛型,是一种数据安全的用法。

2. 集合框架图

Java的集合框架从整体上可以分为两大家族。

1、 Collection(接口)家族。该接口下的所有子孙均存储的是单一对象。 Add(s)
2、 Map(接口)家族。该接口下的所有子孙均存储的是key-value(键值对)形式的数据。
Put(key,value)

另外还有三个分支,均是为上述两大家族服务的。
1、 Iterator(迭代器)家族。主要用于遍历Colleciton接口的及其子类而设计。
2、 Comparator(比较器), 在集合中存储对象时候,用于对象之间的比较
3、 Collecitons是工具类。注意该类名带个s,一般就表示工具类。里面提供了N多静态方法,来对Colleciton集合进行操作。
在这里插入图片描述

3. Collection接口

3.1 Collection接口概述

Collection接口-定义了存取对象的方法。有两个非常常用的子接口:

List接口:存放的元素有序且允许有重复的集合接口。

Set接口:存放的元素无序不包含重复的集合接口。

说明:

“有序”-元素存入的顺序与取出的顺序相同.

“无序”—元素存入的顺序与取出的顺序不相同

3.2 Collection接口中的常用方法

方法名说明
int size();返回此collection中的元素数。
boolean isEmpty();判断此collection中是否包含元素。
boolean contains(Object obj);判断此collection是否包含指定的元素。
boolean contains(Collection c);判断此collection是否包含指定collection中的所有元素。
boolean add(Object element);向此collection中添加元素。
boolean addAll(Collection c);将指定collection中的所有元素添加到此collection中
boolean remove(Object element);从此collection中移除指定的元素。
boolean removeAll(Collection c);移除此collection中那些也包含在指定collection中的所有元素。
void clear();移除些collection中所有的元素。
boolean retainAll(Collection c);仅保留此collection中那些也包含在指定collection的元素。
Iterator iterator();返回在此collection的元素上进行迭代的迭代器。
Object[] toArray();把此转成数组。

3.3 List接口

3.3.1 List接口概述

List中的元素是有序的,且允许重复。(因为List接口中添加了许多针对下标操作的方法)

实现类:

  1. ArrayList
  2. LinkedList
  3. Vector
  4. Stack
3.3.2 List接口相比Collection接口的新增方法
方法名说明
public Object get(int index)根据下标,返回列表中的元素
public Object add(int index, Object element);在列表的指定位置插入指定元素.将当前处于该位置的元素(如果有的话)和所有后续元素向右移动
public Object set(int index, Object element) ;用指定元素替换列表中指定位置的元素
public Object remove(int index)移除列表中指定位置的元素

注意:list集合中的元素的索引与数组中元素的索引一样,均是从0开始。

3.3.3 List实现类之ArrayList集合

ArrayList相比数组的区别?容量的可扩展性,数据类型只要是Object类型就行,存储的必须是对象,不能存储基础数据类型。

package com.dream.arrayList;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class Test02 {

	public static void main(String[] args) {
		/**
		 * 知识点:使用ArrayList方法 + 泛型
		 * 
		 * 泛型:数据安全的作法,规定集合应该存储什么样的数据类型
		 */
		ArrayList<String> list = new ArrayList<>();
		
		//添加元素
		list.add("麻生希");
		list.add("椎名空");
		list.add("爱田奈奈");
		list.add("三上悠亚");
		list.add("明日花绮罗");
		
		//获取元素的个数
		int size = list.size();
		System.out.println("获取元素的个数:" + size);//5
		
		//设置指定下标上的元素
		list.set(0, "张三");
		
		//获取指定下标上的元素
		String elment = list.get(0);
		System.out.println("获取指定下标上的元素:" + elment);//张三
		
		//在指定下标上插入元素
		list.add(1, "李四");
		
		ArrayList<String> newList1 = new ArrayList<>();
		Collections.addAll(newList1, "aaa","bbb","ccc","明日花绮罗");//利用集合工具类进行批量添加
		list.addAll(newList1);//将新集合中所有的元素添加到指定集合的末尾
		
		ArrayList<String> newList2 = new ArrayList<>();
		Collections.addAll(newList2, "ddd","eee","fff");//利用集合工具类进行批量添加
		list.addAll(3, newList2);//将新集合中所有的元素添加到指定集合上指定下标的位置
		
		//清空集合中所有的元素
		//list.clear();
		
		System.out.println("判断集合中是否包含某个元素:" + list.contains("椎名空"));//true
		
		ArrayList<String> newList3 = new ArrayList<>();
		Collections.addAll(newList3, "eee","ddd","fff","ggg");//利用集合工具类进行批量添加
		System.out.println("判断集合中是否包含某个集合中所有元素:" + list.containsAll(newList3));//false
		
		int index = list.indexOf("椎名空");
		System.out.println("获取元素在集合中的下标:" + index);
		
		boolean empty = list.isEmpty();//有元素-false 没有元素-true
		System.out.println("判断集合中是否没有元素:" + empty);//false
		
		//删除
		list.remove(3);//依据下标删除元素
		list.remove("eee");//依据元素删除元素
		
		//删除 - 去交集
		ArrayList<String> newList4 = new ArrayList<>();
		Collections.addAll(newList4, "fff","aaa","bbb","xxx");//利用集合工具类进行批量添加
		list.removeAll(newList4);
		
		//保留交集	
		ArrayList<String> newList5 = new ArrayList<>();
		Collections.addAll(newList5, "张三","李四","椎名空","爱田奈奈","三上悠亚","yyy");//利用集合工具类进行批量添加
		list.retainAll(newList5);
		
		//替换指定下标上的元素
		list.set(2, "深田咏美");
		
		//获取开始下标(包含)到结束下标(不包含)的元素,返回新的集合	
		List<String> subList = list.subList(1, 3);
		
		//将集合转换为数组
		Object[] array = subList.toArray();
		System.out.println(Arrays.toString(array));
		
		System.out.println("-------------");
		
		//遍历 - for
		for (int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}
		
		System.out.println("-------------");
		
		//遍历 - foreach
		for (String element : list) {
			System.out.println(element);
		}
		
		System.out.println("-------------");
		
		//遍历 - Iterator迭代器
		Iterator<String> it = list.iterator();//获取Iterator迭代器对象
		while(it.hasNext()){//判断是否有可迭代的元素
			String e = it.next();//返回下一个元素
			System.out.println(e);
		}
		
		System.out.println("-------------");
		
		//遍历 - ListIterator迭代器
		ListIterator<String> listIterator = list.listIterator();//获取ListIterator迭代器对象
		while(listIterator.hasNext()){//判断是否有可迭代的元素
			String e = listIterator.next();//返回下一个元素
			System.out.println(e);
		}	
	}
}
3.3.4 List实现类之LinkedList集合

LinkedList集合和ArrayList在使用上没有区别,只是LinkedList在ArrayList的基础上还多了一些方法,LinkedList有特有的队列模式和栈模式

package com.dream.linkedList;

import java.util.LinkedList;

public class Test02 {

	public static void main(String[] args) {
		/**
		 * 知识点:LinkedList 队列模式
		 * 
		 * 特点:先进先出
		 */
		
		LinkedList<String> linkedList1 =new LinkedList<>();
		
		linkedList1.add("小明");
		linkedList1.add("张三");
		linkedList1.add("王五");
		linkedList1.add("李四");
		linkedList1.add("小胖");
		
		while(!linkedList1.isEmpty()) {
			//删除第一个元素,并返回
			String removeFirst = linkedList1.removeFirst();
			System.out.println(removeFirst);
		}
		System.out.println("集合中元素的个数:" + linkedList1.size());
		System.out.println("----------------------");
		
		
		/**
		 * 知识点:LinkedList 队列模式
		 * 
		 * 特点:先进后出
		 */
		LinkedList<String> linkedList2 = new LinkedList<>();
		
		linkedList2.add("小明");
		linkedList2.add("张三");
		linkedList2.add("王五");
		linkedList2.add("李四");
		linkedList2.add("小胖");
		
		while(!linkedList2.isEmpty()){
			
			String removeLast = linkedList2.removeLast();
			System.out.println(removeLast);
		}
		System.out.println("集合中元素的个数:" + linkedList2.size());
		
	}
}

/*
LinkedList的队列模式和栈模式拿一个元素,集合对象里就少一个元素
输出结果:
    小明
    张三
    王五
    李四
    小胖
    集合中元素的个数:0
    ----------------------
    小胖
    李四
    王五
    张三
    小明
    集合中元素的个数:0
*/
3.3.5 ArrayList和LinkedList集合的区别

1.数据结构不同:

​ ArrayList是Array(动态数组)的数据结构,LinkedList是Link(链表)的数据结构。

2.效率不同:

​ 当随机访问List(get和set操作)时,ArrayList比LinkedList的效率更高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。

​ 当对数据进行增加和删除的操作(add和remove操作)时,LinkedList比ArrayList的效率更高,因为ArrayList是数组,所以在其中进行增删操作时,会对操作点之后所有数据的下标索引造成影响,需要进行数据的移动。

3.自由性不同

​ ArrayList自由性较低,因为它需要手动的设置固定大小的容量,但是它的使用比较方便,只需要创建,然后添加数据,通过调用下标进行使用;而LinkedList自由性较高,能够动态的随数据量的变化而变化,但是它不便于使用。

4.控件开销不同

​ ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间

3.3.6 Vector集合

​ 在List 接口中还有一个实现类:Vector。Vector类从整个 Java 的集合发展历史来看,Vector算是一个元老级的类,在 JDK1.0 的时候就已经存在此类。但是到了Java2(JDK1.2)之后重点强调了集合框架的概念,所以先后定义了很多的新接口(如:List 等)。但是考虑到一大部分的人已经习惯了使用 Vector类,因此设计者就让 Vector 类多实现了一个 List接口,这样才将其保留下来。但是因为其是 List 接口的子类,所以 Vector 类的使用与之前的并没有太大的区别。但是Vector内部有一些比较老的方法名比较长的方法。

在这里插入图片描述

Vector是线程安全的集合,但是一般不建议使用

Vector在使用上由于都是继承了List接口,所以使用上没有太大区别,主要介绍一下它自己的老方法

package com.dream.vector;

import java.util.Enumeration;
import java.util.Vector;

public class Test02 {
	
	public static void main(String[] args) {
		/**
		 * 知识点:Vector老的方法
		 */
		
		Vector<String> v = new Vector<>();
		
		//添加元素
		v.addElement("aa");
		v.addElement("bb");
		v.addElement("cc");
		v.addElement("dd");
		
		//删除
		v.removeElement("bb");//依据元素删除元素
		v.removeElementAt(2);//依据下标山存储元素
		
		//遍历
		Enumeration<String> elements = v.elements();
		while(elements.hasMoreElements()){
			String nextElement = elements.nextElement();
			System.out.println(nextElement);
		}
	}
}
3.3.6.1 Stack集合

Vector提供一个Stack子类,它用于模拟了“栈”这种数据结构,“栈”通常是指“后进先出”(LIFO)

package com.dream.stack;

import java.util.Stack;

public class Test01 {
	
	public static void main(String[] args) {
		/**
		 * 知识点:Stack
		 * 特点:栈模式 - 先进后出
		 */
		
		Stack<String> stack = new Stack<>();
		
		//添加元素 - 将元素压入栈顶
		stack.push("aa");
		stack.push("bb");
		stack.push("cc");
		stack.push("dd");
		
		System.out.println("距离栈顶的位置(从1开始):" + stack.search("bb"));
		
		while(!stack.empty()){
			//获取栈顶第一个元素,并返回
			//String element = stack.peek();
			
			//删除栈顶第一个元素,并返回
			String element = stack.pop();
			System.out.println(element);
		}
		System.out.println(stack.size());
	}
}
//也是属于拿一个就少一个的集合

3.4 泛型

含义:数据安全点的作用

package com.dream.generic;

import java.util.ArrayList;

public class Test02 {
	
	public static void main(String[] args) {
		/**
		 * 知识点:泛型限定
		 */
	}
	
	//?:任何类型
	public ArrayList<?> method01(){
		ArrayList<String> list = new ArrayList<>();
		return list;
	}
	
	//? extends A
	//?:表示A的子类或者A类
	public ArrayList<? extends A> method02(){
//		ArrayList<B> list = new ArrayList<>();
		ArrayList<A> list = new ArrayList<>();
		return list;
	}
	
	//? super A
	//?:表示A的父类或A类
	public ArrayList<? super A> method03(){
//		ArrayList<Object> list = new ArrayList<>();
		ArrayList<A> list = new ArrayList<>();
		return list;
    }
}

3.5 迭代器

3.5.1 Iterator迭代器
package com.dream.iterator;

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

public class Test02 {
	
	public static void main(String[] args) {
		/**
		 * 知识点:Iterator迭代器
		 * 
		 * 需求:向ArrayList中添加元素("aa","bb","cc","dd"),
		 * 	        使用Iterator迭代器遍历,bb,删除该元素
		 */
		
		ArrayList<String> list = new ArrayList<>();
		
		list.add("aa");
		list.add("bb");
		list.add("cc");
		list.add("dd");
		
		Iterator<String> it = list.iterator();
		while (it.hasNext()) {
			String element = it.next();
			if(element.equals("bb")){
				//list.remove(element); 这个会报异常原因后面分析
				it.remove();
			}
		}	
		for (String element : list) {
			System.out.println(element);
		}	
	}
}

上述举例关于遍历里面要删除元素用list.remove()会报错的原因涉及到了iterator的底层源码,源码如下

public abstract class AbstractList<E>{
    
    //操作数 - 5
    protected transient int modCount = 0;
}

public class ArrayList<E> extends AbstractList<E> implements List<E>{
    
    private int size;//4
    
    //ArrayList所有的元素都放在此数组中
    transient Object[] elementData;
    
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
    
    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }
    
    //因为Iterator是接口,所以返回的是该接口实现类的对象
    public Iterator<E> iterator() {
        return new Itr();
    }
    
     private class Itr implements Iterator<E> {
        int cursor;       //0
        int lastRet = -1; // -1
        int expectedModCount = modCount;//expectedModCount - 4

        //判断是否有可迭代的元素
        public boolean hasNext() {
            //cursor - 2
            //size - 4
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            //判断操作数是否和内部操作数相同
            checkForComodification();
            //i = 1
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            //cursor - 2
            cursor = i + 1;
            //lastRet - 1
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                //利用外部类对象调用remove方法(调用的ArrayList的remove方法)
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                //保证操作数和内部操作数一致
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        //判断操作数 和 内部操作数是否相同
        final void checkForComodification() {
            if (modCount != expectedModCount)
                //报错
                throw new ConcurrentModificationException();
        }
    }
}

首先是ArrayList这个类继承了它的父类AbstractList,在这个父类中有一个modCount这个变量,这个变量表示的是操作数,初始值为0,什么是操作数?也就是说关于arraylist这个集合每进行一次操作,例如add,remove等等这样的操作这个操作数就会+1,要生成迭代器就要用集合对象去调用iterator方法,而这个方法返回的是一个Iterator接口的实现类Itr的对象,在Itr这个类里面,我们可以看到有三个变量,cursor表示游标,lastRet,还有一个expectedModCount,这个可以当做是内部的操作数,可以看到这个内部的操作数的值是由modCount赋值的,也就是说我们这个案例的上述代码这个modCount在进行了四次add方法过后值为4

while (it.hasNext()) {
    String element = it.next();
    if(element.equals("bb")){
        //list.remove(element);
        it.remove();
    }
}

这个hasNext方法是判断size和cursor是否相等,size也就是这个集合的长度,如果不相等就返回true,也就是说当cursor这个游标一直往下直到超过了这个集合长度就返回false那么这个while循环也就停止了,现在来分析这个Next方法

public E next() {
    checkForComodification();
    int i = cursor;
    if (i >= size)
        throw
        new NoSuchElementException();
    Object[] elementData = ArrayList.this.elementData;
    if (i >= elementData.length)
        throw new ConcurrentModificationException();
    cursor = i + 1;
    return (E) elementData[lastRet = i];
}
final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

这个方法首先是调用checkForComodification这个方法,这个方法是来判断内部操作数和操作数是否相等,如果不相等会直接抛异常,这个内部操作数在最开始是由操作数来赋值的,只要操作数在后期不改变就不会抛异常,i的初值是由游标来赋值的,如果i>=size 也就是游标已经超过了size这个集合长度了,也就是说这个迭代器已经把元素迭代完了,迭代器里已经没有元素了,那么就会报异常NoSuchElementException,如果不报异常后面正常执行,把i+1赋值给游标,也就是让游标依次往后移,返回值是elementData[lastRet = i],这个也就是当前指向的元素进行返回。
现在来分析报异常:

在while循环里用list.remove(“bb”);用集合对象调用了remove方法,操作数+1了 也就是说 最开始操作数是4,现在变成了5,而内部操作数还是4,那么在调用Next方法时,要调用checkForComodification这个方法来判断操作数和内部操作数是否一致,这是内部操作室是4,操作数是5,此时就会报异常,而集合里面的元素其实已经删掉了,那么为什么要这样设计呢?

因为:我们遍历的目的是浏览数据,而删除是改变数据,在浏览数据时我们为了保证数据的一致性和不会有脏数据的出现所以不能删除数据

用迭代器对象调用的remove方法不会报异常的原因是在remove方法中进行了异常的处理expectedModCount = modCount;讲操作数重新赋值给了内部操作数,保证了操作数的一致

3.5.2 ListIterator迭代器
package com.dream.iterator;

import java.util.ArrayList;
import java.util.ListIterator;

public class Test03 {
	
	public static void main(String[] args) {
		/**
		 * 知识点:ListIterator迭代器
		 * 
		 * 需求:向ArrayList中添加元素("aa","bb","cc","dd"),
		 * 	        使用ListIterator迭代器遍历,bb,替换该元素或增加一个元素
		 */
		
		ArrayList<String> list = new ArrayList<>();
		
		list.add("aa");
		list.add("bb");
		list.add("cc");
		list.add("dd");
		
		ListIterator<String> listIterator = list.listIterator();
		while(listIterator.hasNext()){
			String element = listIterator.next();
			if(element.equals("bb")){
				//listIterator.set("ee");
                listIterator.add("ee");
			}
		}		
		for (String element : list) {
			System.out.println(element);
		}	
	}
}
package com.dream.iterator;

import java.util.ArrayList;
import java.util.ListIterator;

public class Test06 {
	
	public static void main(String[] args) {
		/**
		 * 知识点:ListIterator迭代器
		 * 
		 * 需求:向ArrayList中添加元素("aa","bb","cc","dd"),
		 * 	   	倒叙输出
		 */
		
		ArrayList<String> list = new ArrayList<>();
		
		list.add("aa");
		list.add("bb");
		list.add("cc");
		list.add("dd");
		
		ListIterator<String> listIterator = list.listIterator(list.size());
		while(listIterator.hasPrevious()){//判断前面是否有可迭代的元素
			String element = listIterator.previous();//返回上一个元素
			System.out.println(element);
		}
	}
}
3.5.3 Iterator和ListIterator的区别

Iterator :Collection接口下所有的实现类都可以获取的迭代器,可以在遍历时删除元素

ListIterator :只能是List接口下的实现类才可以获取的迭代器,可以在遍历时删除、替换、添加元素,也可以指定下标开始遍历,还可以倒叙遍历

3.6 Set 接口

特点:无序且不可重复

实现类:

  1. HashSet
  2. LinkedHashSet
  3. TreeSet
3.6.1 HashSet集合

不能保证元素的排列顺序,顺序有可能发生变化

首先HashSet这个集合是怎么确保元素不重复呢?

首先根据对象的hashcode方法得到hash码然后在按照算法来得到该对象要存放的下标,如果这个下标没有存放元素,那么直接存放进去,如果有元素了,则通过equals方法进行比较,如果值为true那么就被视为重复的对象,就不会进行添加。

如下图:
在这里插入图片描述

package com.dream.hashset;

import java.util.HashSet;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;

public class Test01 {

	public static void main(String[] args) {
		/**
		 * 知识点:使用HashSet方法
		 * 
		 * 特点:无序且不可重复
		 */
		
		HashSet<String> set = new HashSet<>();
		
		//添加元素
		set.add("麻生希");
		set.add("椎名空");
		set.add("爱田奈奈");
		set.add("三上悠亚");
		set.add("明日花绮罗");
		
		//获取元素的个数
		int size = set.size();
		System.out.println("获取元素的个数:" + size);//5

		HashSet<String> newSet1 = new HashSet<>();
		Collections.addAll(newSet1, "aaa","bbb","ccc","明日花绮罗");//利用集合工具类进行批量添加
		set.addAll(newSet1);//将新集合中所有的元素添加到指定集合的末尾
		
		//清空集合中所有的元素
		//set.clear();
		
		System.out.println("判断集合中是否包含某个元素:" + set.contains("椎名空"));//true
		
		HashSet<String> newSet2 = new HashSet<>();
		Collections.addAll(newSet2, "eee","ddd","fff","ggg");//利用集合工具类进行批量添加
		System.out.println("判断集合中是否包含某个集合中所有元素:" + set.containsAll(newSet2));//false
		
		boolean empty = set.isEmpty();//有元素-false 没有元素-true
		System.out.println("判断集合中是否没有元素:" + empty);//false
		
		//删除
		set.remove("爱田奈奈");//依据元素删除元素
		
		//删除 - 去交集
		HashSet<String> newSet3 = new HashSet<>();
		Collections.addAll(newSet3, "fff","aaa","bbb","xxx");//利用集合工具类进行批量添加
		set.removeAll(newSet3);
		
		//保留交集	
		HashSet<String> newSet4 = new HashSet<>();
		Collections.addAll(newSet4, "aa","bb","椎名空","爱田奈奈","三上悠亚","yyy");//利用集合工具类进行批量添加
		set.retainAll(newSet4);
		
		//将集合转换为数组
		Object[] array = set.toArray();
		System.out.println(Arrays.toString(array));
		
		System.out.println("-------------");
		
		//遍历 - foreach
		for (String element : set) {
			System.out.println(element);
		}
		
		System.out.println("-------------");
		
		//遍历 - Iterator迭代器
		Iterator<String> it = set.iterator();//获取Iterator迭代器对象
		while(it.hasNext()){//判断是否有可迭代的元素
			String e = it.next();//返回下一个元素
			System.out.println(e);
		}	
	}
}
3.6.2 LinkedHashSet集合

1.底层使用了LinkedHshMap

  • LinkedHashMap是HashMap的一个子类,具有和HashMap相同的存储结构和扩容机制,在此基础上增加了head(头节点)和tail(尾节点)

2.LinkedHshMap底层数据结构

  • Entry 类型数组 + 单向链表 + 双向链表 + 红黑树
  • Entry 类型数组 继承了 hashmap 的node结构,增加了Entry<K,V> before, after两个属性
  • 单向链表 用于维护数组的每一个Entry元素的链表关系
  • 双向链表 通过新增的before和after属性进行控制,主要实现了插入顺序和读取顺序保持一致
  • 红黑树 用于把过长的单向链表结构树化
//这是LinkedHshSet关于add方法的部分底层源码
public class HashSet<E> extends AbstractSet<E> implements Set<E>{
    private transient HashMap<E,Object> map;
    
    public boolean add(E e) {
    	return map.put(e, PRESENT)==null;
	}
}
package com.dream.linkedhashset;

import java.util.LinkedHashSet;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;

public class Test01 {

	public static void main(String[] args) {
		/**
		 * 知识点:使用LinkedHashSet方法
		 * 
		 * 特点:去重+有序
		 */
		
		LinkedHashSet<String> set = new LinkedHashSet<>();
		
		//添加元素
		set.add("麻生希");
		set.add("椎名空");
		set.add("爱田奈奈");
		set.add("三上悠亚");
		set.add("明日花绮罗");
		
		//获取元素的个数
		int size = set.size();
		System.out.println("获取元素的个数:" + size);//5

		LinkedHashSet<String> newSet1 = new LinkedHashSet<>();
		Collections.addAll(newSet1, "aaa","bbb","ccc","明日花绮罗");//利用集合工具类进行批量添加
		set.addAll(newSet1);//将新集合中所有的元素添加到指定集合的末尾
		
		//清空集合中所有的元素
		//set.clear();
		
		System.out.println("判断集合中是否包含某个元素:" + set.contains("椎名空"));//true
		
		LinkedHashSet<String> newSet2 = new LinkedHashSet<>();
		Collections.addAll(newSet2, "eee","ddd","fff","ggg");//利用集合工具类进行批量添加
		System.out.println("判断集合中是否包含某个集合中所有元素:" + set.containsAll(newSet2));//false
		
		boolean empty = set.isEmpty();//有元素-false 没有元素-true
		System.out.println("判断集合中是否没有元素:" + empty);//false
		
		//删除
		set.remove("爱田奈奈");//依据元素删除元素
		
		//删除 - 去交集
		LinkedHashSet<String> newSet3 = new LinkedHashSet<>();
		Collections.addAll(newSet3, "fff","aaa","bbb","xxx");//利用集合工具类进行批量添加
		set.removeAll(newSet3);
		
		//保留交集	
		LinkedHashSet<String> newSet4 = new LinkedHashSet<>();
		Collections.addAll(newSet4, "aa","bb","椎名空","爱田奈奈","三上悠亚","yyy");//利用集合工具类进行批量添加
		set.retainAll(newSet4);
		
		//将集合转换为数组
		Object[] array = set.toArray();
		System.out.println(Arrays.toString(array));
		
		System.out.println("-------------");
		
		//遍历 - foreach
		for (String element : set) {
			System.out.println(element);
		}
		
		System.out.println("-------------");
		
		//遍历 - Iterator迭代器
		Iterator<String> it = set.iterator();//获取Iterator迭代器对象
		while(it.hasNext()){//判断是否有可迭代的元素
			String e = it.next();//返回下一个元素
			System.out.println(e);
		}
	}
}
//最后输出结果是有序的,也就是说添加元素的时候的顺序是什么,输出结果顺序就是什么
3.6.3 TreeSet集合
package com.dream.treeset;

import java.util.TreeSet;

public class Test02 {
	
	public static void main(String[] args) {
		/**
		 * 知识点:TreeSet排序
		 * 需求:创建两个TreeSet对象,分别存Integer、String
		 * TreeSet:自然排序(根据不同的类型,选择不同排序规则)
		 * TreeSet存Integer:数字排序
		 * TreeSet存String:字典排序
		 */
		
		TreeSet<Integer> set1 = new TreeSet<>();
		set1.add(5);//Integer.valueOf(5);
		set1.add(1);//Integer.valueOf(1);
		set1.add(4);//Integer.valueOf(4);
		set1.add(2);//Integer.valueOf(2);
		set1.add(6);//Integer.valueOf(6);
		set1.add(3);//Integer.valueOf(3);
		set1.add(3);//Integer.valueOf(3);
		for (Integer integer : set1) {
			System.out.println(integer);
		}
		System.out.println("----------");
		TreeSet<String> set2 = new TreeSet<>();
		set2.add("c");
		set2.add("d");
		set2.add("a");
		set2.add("b");
		for (String string : set2) {
			System.out.println(string);
		}
	}
}
/*
输出结果:
	1
    2
    3
    4
    5
    6
    ----------
    a
    b
    c
    d
*/

3.7 比较器接口

作用:排序时使用

分类:

​ 内置比较器:Comparable - compareTo()

​ 外置比较器:Comparator - compare()

使用场景:

​ 内置比较器:对象要想存入TreeSet、TreeMap中,对象所属的类必须要实现内置比较器

​ 外置比较器:当内置比较的规则不满足现在的需求,但又不能改动内置比较器规则时

优先级别:外置比较器 > 内置比较器

案例:
package com.dream.treeset;

public class Student implements Comparable<Student>{
	
	private String name;
	private char sex;
	private int age;
	private String classId;
	private String id;
	
	public Student() {
	}
	
	public Student(String classId, String id) {
		this.classId = classId;
		this.id = id;
	}

	public Student(String name, char sex, int age, String classId, String id) {
		this.name = name;
		this.sex = sex;
		this.age = age;
		this.classId = classId;
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public char getSex() {
		return sex;
	}

	public void setSex(char sex) {
		this.sex = sex;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getClassId() {
		return classId;
	}

	public void setClassId(String classId) {
		this.classId = classId;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}
	
	@Override
	public boolean equals(Object obj) {
		if(this == obj){
			return true;
		}
		if(obj instanceof Student){
			Student stu = (Student) obj;
			if(this.classId.equals(stu.classId) && this.id.equals(stu.id)){
				return true;
			}
		}
		return false;
	}

	@Override
	public String toString() {
		return name + "\t" + sex + "\t" + age + "\t" + classId + "\t" + id;
	}

	//比较规则
	//需求:按照年龄排序
	@Override
	public int compareTo(Student o) {
		if(this.age - o.age != 0) {
			return this.age - o.age;
		}
		return 1;
	}
}
内置比较器—Comparable
package com.dream.treeset;

import java.util.TreeSet;

public class Test03 {
	
	public static void main(String[] args) {
		/**
		 * 知识点:TreeSet排序
		 * 
		 * 理解二叉树的网站 :
		 * 
		 * 需求:创建TreeSet对象,存储Student 
		 * 
		 * Comparable - 内置比较器
		 */
		
		TreeSet<Student> set = new TreeSet<>();
		
		set.add(new Student("麻生希", '女', 26, "2107", "001"));
		set.add(new Student("北岛玲", '女', 31, "2107", "002"));
		set.add(new Student("水菜类", '女', 29, "2107", "003"));
		set.add(new Student("樱井步", '女', 26, "2107", "004"));
		set.add(new Student("朝桐光", '女', 33, "2107", "005"));
		set.add(new Student("椎名空", '女', 29, "2107", "006"));
		set.add(new Student("爱田奈奈", '女', 34, "2107", "007"));
		set.add(new Student("水野朝阳", '女', 26, "2107", "008"));
		set.add(new Student("小峰由衣", '女', 29, "2107", "009"));
		set.add(new Student("古川伊织", '女', 25, "2108", "001"));
		set.add(new Student("吉泽明步", '女', 27, "2108", "002"));
		set.add(new Student("三上悠亚", '女', 24, "2108", "003"));
		set.add(new Student("深田咏美", '女', 24, "2108", "004"));
		set.add(new Student("泷泽萝拉", '女', 29, "2108", "005"));
		set.add(new Student("濑亚美莉", '女', 29, "2108", "006"));
		
		for (Student stu : set) {
			System.out.println(stu);
		}
	}
}
外置比较器-----Comparator
package com.dream.treeset;

import java.util.Comparator;
import java.util.TreeSet;

public class Test04 {
	
	public static void main(String[] args) {
		/**
		 * 知识点:TreeSet排序
		 * 
		 * 需求:创建TreeSet对象,存储Student,按照名字长度排序,长度一致按照年龄排序
		 * 
		 * Comparator - 外置比较器
		 * 
		 */
		
		TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() {

			@Override
			public int compare(Student o1, Student o2) {
				if(o1.equals(o2)){
					return 0;
				}
				if(o1.getName().length() != o2.getName().length()){
					return o1.getName().length() - o2.getName().length();
				}
				if(o1.getAge() != o2.getAge()){
					return o1.getAge() - o2.getAge();
				}
				return 1;
			}
		});
		
		set.add(new Student("吉泽明步", '女', 27, "2108", "002"));
		set.add(new Student("三上悠亚", '女', 24, "2108", "003"));
		set.add(new Student("麻生希", '女', 26, "2107", "001"));
		set.add(new Student("北岛玲", '女', 31, "2107", "002"));
		set.add(new Student("水菜类", '女', 29, "2107", "003"));
		set.add(new Student("古川伊织", '女', 25, "2108", "001"));
		set.add(new Student("椎名空", '女', 29, "2107", "006"));
		set.add(new Student("爱田奈奈", '女', 34, "2107", "007"));
		set.add(new Student("水野朝阳", '女', 26, "2107", "008"));
		set.add(new Student("樱井步", '女', 26, "2107", "004"));
		set.add(new Student("朝桐光", '女', 33, "2107", "005"));
		set.add(new Student("小峰由衣", '女', 29, "2107", "009"));
		set.add(new Student("深田咏美", '女', 24, "2108", "004"));
		set.add(new Student("泷泽萝拉", '女', 29, "2108", "005"));
		set.add(new Student("濑亚美莉", '女', 29, "2108", "006"));
		
		for (Student stu : set) {
			System.out.println(stu);
		}
	}
}

4. Collections集合工具类

package com.dream.conllections;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class Test01 {

	public static void main(String[] args) {
		
		/**
		 * 知识点:Collections - 集合工具类
		 */
		
		ArrayList<Integer> arrayList = new ArrayList<>();
		
		//批量添加
		Collections.addAll(arrayList, 1,25,3,65,5,3,4,6,7);
		
		//排序使用内置比较器
		Collections.sort(arrayList);
		
		//排序使用外置比较器
		Collections.sort(arrayList, new Comparator<Integer>() {

			@Override
			public int compare(Integer o1, Integer o2) {
				
				return o2 - o1;
			}
		});
		
		//替换
		Collections.fill(arrayList, 5);
		
		System.out.println(arrayList);
	}
}

Student(“爱田奈奈”, ‘女’, 34, “2107”, “007”));
set.add(new Student(“水野朝阳”, ‘女’, 26, “2107”, “008”));
set.add(new Student(“樱井步”, ‘女’, 26, “2107”, “004”));
set.add(new Student(“朝桐光”, ‘女’, 33, “2107”, “005”));
set.add(new Student(“小峰由衣”, ‘女’, 29, “2107”, “009”));
set.add(new Student(“深田咏美”, ‘女’, 24, “2108”, “004”));
set.add(new Student(“泷泽萝拉”, ‘女’, 29, “2108”, “005”));
set.add(new Student(“濑亚美莉”, ‘女’, 29, “2108”, “006”));

	for (Student stu : set) {
		System.out.println(stu);
	}
}

}


## 4. Collections集合工具类

```java
package com.dream.conllections;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class Test01 {

	public static void main(String[] args) {
		
		/**
		 * 知识点:Collections - 集合工具类
		 */
		
		ArrayList<Integer> arrayList = new ArrayList<>();
		
		//批量添加
		Collections.addAll(arrayList, 1,25,3,65,5,3,4,6,7);
		
		//排序使用内置比较器
		Collections.sort(arrayList);
		
		//排序使用外置比较器
		Collections.sort(arrayList, new Comparator<Integer>() {

			@Override
			public int compare(Integer o1, Integer o2) {
				
				return o2 - o1;
			}
		});
		
		//替换
		Collections.fill(arrayList, 5);
		
		System.out.println(arrayList);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值