JavaSe——8、Set、List和Queue

来源:互联网 发布:日语网络 编辑:程序博客网 时间:2024/05/31 05:28

Set

特性:

  • 继承Collection接口,和Collection接口中的方法一样,但是不允许元素重复(通过equals判断)。其中的方法大多是在Map集合上的操作。

重要源码解析:

public interface Set<E> extends Collection<E> {}

HashSet

特性:

  • Hash算法存储集合中的元素,存取查找性能好(hashcode值作为索引)。
  • 由于hash算法计算存储位置,因此不能保证顺序;
  • 不同步(需要程序控制保证同步);元素可以为null。
  • HashSet在add时,equals和hashcode都相等才会判断为重复,因此如果某个类的对象保存在HashSet,要保证equals相等时hashcode也相等。
  • 针对HashSet如何重写hashcode:

    • 同一对象的多次hashcode调用返回值应相等。
    • 两个对象equals和hashcode返回的应该一样。
  • hashset的构造函数用的都是hashMap,add和remove等方法也都是调用Map的操作。

重要源码解析:

public class HashSet<E>    extends AbstractSet<E>    implements Set<E>, Cloneable, java.io.Serializable{    private transient HashMap<E,Object> map;   //final对象,初始化时未制定值则默认为null,作为Map的value。    private static final Object PRESENT = new Object();    public HashSet() {        map = new HashMap<>();    }     public boolean add(E e) {        return map.put(e, PRESENT)==null;    }    //制定hash算法的初始容量与负载因子     public HashSet(int initialCapacity, float loadFactor) {        map = new HashMap<>(initialCapacity, loadFactor);    }     public Iterator<E> iterator() {        return map.keySet().iterator();    }      public boolean remove(Object o) {        return map.remove(o)==PRESENT;    }

LinkedHashSet(HashSet的子类)

特性:

  • 根据hashcode决定存储位置,迭代访问性能好。
  • 链表维护次序,因此和HashSet的不同是它是有序的(输出时可保证有序)。
  • 构造函数调用父类HashSet的某个构造函数,内部用LinkedHashMap对象。

重要源码解析:

public class LinkedHashSet<E>    extends HashSet<E>    implements Set<E>, Cloneable, java.io.Serializable {    public LinkedHashSet(int initialCapacity, float loadFactor) {        super(initialCapacity, loadFactor, true);    }    public LinkedHashSet(int initialCapacity) {        super(initialCapacity, .75f, true);    }    public LinkedHashSet() {        super(16, .75f, true);    }}//Super方法:调用HashSet类中的:  HashSet(int initialCapacity, float loadFactor, boolean dummy) {        map = new LinkedHashMap<>(initialCapacity, loadFactor);    }//LinkedHashMap的这个初始化方法:  public LinkedHashMap(int initialCapacity, float loadFactor) {        super(initialCapacity, loadFactor);        accessOrder = false;    }//其中的super方法为HashMap中的:    public HashMap(int initialCapacity, float loadFactor) {        if (initialCapacity < 0)            throw new IllegalArgumentException("Illegal initial capacity: " +                                               initialCapacity);        if (initialCapacity > MAXIMUM_CAPACITY)            initialCapacity = MAXIMUM_CAPACITY;        if (loadFactor <= 0 || Float.isNaN(loadFactor))            throw new IllegalArgumentException("Illegal load factor: " +                                               loadFactor);        this.loadFactor = loadFactor;        this.threshold = tableSizeFor(initialCapacity);    }    

TreeSet(SortedSet)

特性:

  • 根据红黑树的数据结构存储。
  • 插入时会自动排序(调用compareTo方法),所以插入的对象的类必须实现Comparable接口,且TreeSet的元素只能是同一个类的。
    • 1、自然排序:
      调用compareTo方法(Comparable接口里的)。
      把一个对象放入TreeSet,则要重写equeals和compareTo,且结果要一致。
      如果放入的对象修改了值,TreeSet不会改变顺序,因此最好放入不可变对象。

PS:
不可变类: private final修饰属性; 提供带参构造器; 属性提供getter,不提供setter;

有必要就重写equals和hashcode。

实现Comparable接口的类: BigDecimal、Character、Boolean、String、Date、time。

  • end
    • 2、定制排序(new TreeSet时包含一个匿名内部类,用来定制排序规则)

重要源码解析:

public class TreeSet<E> extends AbstractSet<E>    implements NavigableSet<E>, Cloneable, java.io.Serializable

EnumSet

  • 枚举集合类、有序、位向量的形式存储、占内存小、运行效率高、批量处理快、不允许null。通过static方法实例化:allOf、copyOf、range、of等。

对比

  • HashSet性能好(尤其查找,添加)TreeSet适合有序的,但性能一般(红黑树),LinkedHashSet的遍历快。EnumSet性能最好,三个都线程不安全。

List:有序、可重复、可以为null、。

特性:

  • List的remove不用是同一个对象,只要两个对象equals为true则删除。

  • listIterator方法:返回ListIterator对象(继承Iterator接口,增加了hasPrevious、previous,即可以向前迭代集合,)

ArrayList

特性:

  • 封装了一个动态,允许再分配的Object[]数组,默认长度为10;
  • ArrayList:线程不安全;Vector:线程安全。
  • Vector有个子类:Stack,栈,可以peek、pop、push,线程安全,性能烂,想用栈?还是用LinkedList吧。
  • Arrays工具类的asList方法可以将一定个数对象或数组转换为一个List(Arrays内部类AaaryList的实例)

重要源码分析:

public class ArrayList<E> extends AbstractList<E>        implements List<E>, RandomAccess, Cloneable, java.io.Serializable{     //默认大小     private static final int DEFAULT_CAPACITY = 10;     //无参构造函数返回的一个空数组     private static final Object[] EMPTY_ELEMENTDATA = {};    //存元素,通过一个数组维护     transient Object[] elementData;     public ArrayList(int initialCapacity) {        if (initialCapacity > 0) {            this.elementData = new Object[initialCapacity];        } else if (initialCapacity == 0) {            this.elementData = EMPTY_ELEMENTDATA;        } else {            throw new IllegalArgumentException("Illegal Capacity: "+                                               initialCapacity);        }    }      public ArrayList() {        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;    }    //缩容      public void trimToSize() {        modCount++;        if (size < elementData.length) {            elementData = (size == 0)              ? EMPTY_ELEMENTDATA              : Arrays.copyOf(elementData, size);        }    }    //扩容(用Arrays的copy方法,底层是个 System.arraycopy,native方法)    public void ensureCapacity(int minCapacity) {        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)            // any size if not default element table            ? 0            // larger than default for default empty table. It's already            // supposed to be at default size.            : DEFAULT_CAPACITY;        if (minCapacity > minExpand) {            ensureExplicitCapacity(minCapacity);        }    }   }

LinkedList:

特性:

  • 双向链表
  • 实现Deque,可以作为双向队列使用。

重要源码分析:

public class LinkedList<E>    extends AbstractSequentialList<E>    implements List<E>, Deque<E>, Cloneable, java.io.Serializable{    transient int size = 0;     transient Node<E> first;     transient Node<E> last;     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;        }    }

Queue:

  • 队列的模拟,先进先出,不可随机访问。
  • 实现类:PriorityQueue,加入元素后重新排序,先进先出,但出的是最小的元素。不允许有null,和TreeSet一样有两种排序方式。
  • Deque接口(双端接口,也可以当栈),ArrayDeque和LinkedList都是其实现类。
  • ArrayDeque,基于数组实现的双端队列,默认长度为16。
  • ArrayDeque和ArrayList都是封装了数组,而ArrayList封装了链表,适合插删(数组适合随机访问)。

  • ArrayList和LinkedList分别是线性表的两种实现(数组和链),LinkedList有双端队列和栈的功能,链表插删好,数组访问好。