集合:层次结构:
(1)Collection (接口)其常用子接口 Set List Queue
Set 的子接口和其实现类如下
(一)EnumSet (抽象类) implements Set
(二)SortedSet(接口) exntends Set
(三)HashSet implements Set
(一.1)EnumSet的元素加入存储的机制是:当创建EnumSet对象 EnumSet e=new EnumSet(Season.class)时就把Season类型的枚举值赋给EnumSet属性final Enum[] universe了;进行add(Object o)时,先调用typeCheck(e)进行类型检查,如类型不是Season或者其父类时则抛出异常,然后 return elements != oldElements;实际上没有加入任何元素,所以EnumSet中只可以存放相同枚举类型的对象,否则会抛出类型转换异常,
add的源代码如下:
public boolean add(E e) {
typeCheck(e);
long oldElements = elements;
elements |= (1L << ((Enum)e).ordinal());
return elements != oldElements;
}
删除时实际也没有删除任何元素:代码如下
public boolean remove(Object e) {
if (e == null)
return false;
Class eClass = e.getClass();
if (eClass != elementType && eClass.getSuperclass() != elementType)
return false;
long oldElements = elements;
elements &= ~(1L << ((Enum)e).ordinal());
return elements != oldElements;
}
(二.1)TreeSet implements SortedSet
(三.1)LinkedHashSet exntends HashSet
HashSet类中加入元素(可以加入不同类型的元素)的机制是根据其元素的equals(Object o)方法和hashCode()方法来判断是否能够加入新的元素,HashSet中的元素是无序的
LinkedHashSet的原理和HashSet的相同,只是LinkedHashSet是有序的,先加入的排在前面,底层通过链表来维护这种顺序。
由于HashSet和LinkedHashSet类加入和删除元素的机制是根据add(Object obj)加入对象obj的hashCode()的hash值和equals(Object o)进行比较是否可加入新元素或者存在该元素,由于所有的类的hash值都是整数,是可比较的,并且所有类默认的equals(Object o)方法都可以与任何类型的对象进行比较,如果是与不同类型的对象进行比较时,返回的值是false,所以HashSet和LinkedHashSet类中可加入不同类型的元素,如:
package set;
import java.util.HashSet;
import java.util.Iterator;
public class hashset
{
public static void main(String[] args)
{
HashSet h=new HashSet();
h.add("hello");
h.add("world");
h.add("good");
h.add("ddd");
h.add("aaa");
h.add("hello");
h.add(new hashset());
h.add(new Integer(4));
System.out.println(new hashset().hashCode());
Iterator it=h.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
即可加入String类型也可加入hashsett和Integer类型
TreeSet类中加入元素(元素必须是同种类型)的机制是根据其元素对应的类中实现Comparable接口的compareto(Object o)方法来判断是否能够加入新的元素,如果该元素对应的类中没有实现该方法,则TreeSet中能加入一个元素,TreeSet默认是根据compareto(Object o)来对元素进行升序排序,也可以实现定制排序
如 TreeSet
{
@Override
public int compare(R o1, R o2)
{
return o1.count>o2.count?-1:o1.count
});
TreeSet的存储机制是用红黑树进行存储的,如下代码的存储:
package test;
import java.math.BigDecimal;
import java.util.TreeSet;
class R implements Comparable
{
int count;
public R(int count)
{
this.count=count;
}
public String toString()
{
return "R[count:"+count+"]";
}
public boolean equals(Object o)
{
if(this==o)
return true;
if(o!=null&&o.getClass()==R.class)
{
R r=(R)o;
if(this.count==r.count)
return true;
}
return false;
}
@Override
public int compareTo(Object o)
{
R r=(R)o;
return count>r.count?1:count
}
public class Test
{
public static void main(String[] args)
{
TreeSet
t.add(new R(5));
t.add(new R(-3));
t.add(new R(9));
t.add(new R(-2));
System.out.println(t); (1)
R first=t.first();
first.count=20;
R last=t.last();
last.count=-2;
System.out.println(t); (2)
System.out.println(t.remove(new R(-2)));
System.out.println(t);
System.out.println(t.remove(new R(5)));
System.out.println(t);
System.out.println(t.remove(new R(-2)));
System.out.println(t);
}
}
(1)之前的红黑树是这样的:
5
-3 9
-2
(1)-->(2)树添加修改稳定之后,形成的红黑树是这样的:
5
20 -2
-2
第二层-2是20的右子节点,因为删除时循根搜索,-2一直往左路搜,最后搜到20左子节点为空,所以删除失败,待5删除之后,重新平衡了树结构:
-2
20 -2
因此-2就能被删除
TreeSet中删除元素的原理t.remove(Object obj) :
通过调用obj对象对应类中的obj.compareTo(Object obj)方法,按照红黑树搜索的方法来查找,如果存在obj.compareTo(Object obj1)返回值等于0,则删除掉该obj1元素,否则删除不成功
TreeSet中加入不同类型元素的异常问题
package set;
import java.util.Iterator;
import java.util.TreeSet;
public class treeset implements Comparable
{
@Override
public int compareTo(Object o)
{
return 1;
}
public static void main(String[] args)
{
TreeSet t=new TreeSet();
t.add(new Integer(2));//由于还没有元素,所有可以加入
t.add(new Integer(3));//由于t中只存在Integer类型元素,所以可以继续加入
t.add(new treeset());//虽然集合中存在Integer类型元素,但由于treeset中实现了comparaTo(Object o)方法该方法的返回值总是1,所有总是可比较的
//t.add(new String());//出现异常,因为String 中实现的comparaTo(Object o)方法,只可以和String类型比较,由于集合中存在其他类型(Integer和treeset类型),所有抛出类型转换异常
}
}
List 的子接口和其实现类如下 List有序,可重复,可以获得ListIterator it=al.listIterator();ListIterator迭代器,可进行向前迭代
(一)LinkedList implements List
(二)ArrayList implements List
(三)Vector implements List Stack extends Vector
ArrayList 中加入元素的存储机制是根据索引来存储的,每个元素都有一个索引,所以ArrayList中可以加入相同的元素,她们的索引是不同的,并且是有序的,ArrayList删除的原理是根据remove(Object obj)中obj所对应的类的equals(Object o)方法来判断的,如果返回值是true,则删除对应的元素o,由于所有类默认的equals(Object o)方法都可以与任何类型的对象进行比较,如果是与不同类型的对象进行比较时,返回的值是false,所以ArrayList中可加入不同类型的元素,如:
package list;
import java.util.ArrayList;
import java.util.List;
public class arraylist
{
public static void main(String[] args)
{
List l=new ArrayList();
ArrayList al=new ArrayList();
al.add("hello");
al.add("www");
al.add(new arraylist());
al.add(new Integer(4));
al.add("www");
al.add(0, "good");
System.out.println(al.get(3));
}
}
即可加入String类型也可加入arraylist和Integer类型
由于arraylist重写了equals(Object o)方法,并且返回值总是true,所以当remove(Object obj)时总是删除集合中的第一个元素,不管obj是否存在
package list;
import java.util.ArrayList;
import java.util.List;
public class arraylist
{
public boolean equals(Object o)
{
return true;
}
public static void main(String[] args)
{
List l=new ArrayList();
ArrayList al=new ArrayList();
al.add("hello");
al.add("www");
al.add("www");
al.add(0, "good");
al.remove(new arraylist());
al.remove(new arraylist());
System.out.println(al);
}
}
Vector的用法和ArrayList几乎完全相同,Vector是古老的方法,Vector中有比较多的重复的方法,Vector是线程安全的,ArrayList是线程不安全的,尽量少用Vector,如果为了线程安全,则可以通过
ArrayList ar=(ArrayList)Collections.synchronizedList(new ArrayList());来确保ArrayList的线程安全
Stack实现了Vector类,比Vector类多了三个方法push(Object o),入栈,pop()出栈,peek()查看栈顶元素,由于Stack也是古老的方法,所以尽量少用,如果要用“栈”这种数据结构,则可以用LinkedList类
固定长度的List
package list;
import java.util.Arrays;
import java.util.List;
//Arrays的内部类ArrayList的测试,该List是不可变,只能遍历,不能增加和删除
public class Arrays_ArrayList
{
public static void main(String[] args)
{
//=Arrays.asList(T... a)返回的是Arrays的内部类ArrayList,而不是由实现了List接口的ArrayList、LinkedList或者Vector
List l=Arrays.asList("heelo","good");//该集合中的元素是用/Arrays的内部类ArrayList的 private final E[] a属性来存放的;由于a是final修饰的,所以不能删除a中的元素;
//l.remove(0);抛出异常
System.out.println(l);
l.set(0, "wolrd");//可以改里面的元素内容
}
}
Queue 的子接口和实现类如下:
(一)Deque extends Queue LinkedList implements Deque
(二) PriorityQueue implements Queue
LinkedList 加入是根据索引加入,所以能加入重复元素,删除remove(Object o)是根据元素o所对应的类的equals方法来查找删除的,所以可以加入不同类型的元素
PriorityQueue 加入元素的策略是通过队列中元素对应类的compareTo(Object o)方法进行比较,升序排序,当加入的元素比对尾的元素小时则和队尾的元素交换位置,直到找到该元素的存放位置为止,如果加入的元素大于或者等于队尾元素时,则直接把该元素加入到队尾,所以可以加入值相等的元素,由于不同类实现的compareTo(Object o)方法只能进行同种类型对象的比较,所以PriorityQueue 中只能加入同种类型的数据
加入的底层代码实现如下:
PriorityQueue q=new PriorityQueue();
q.add(8);
q.add(8);
public boolean add(E e) {
return offer(e);
}
add调用了offer(e)方法
offer(e)的方法如下
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;
int i = size;
if (i >= queue.length)
grow(i + 1);
size = i + 1;
if (i == 0)
queue[0] = e;
else
siftUp(i, e);
return true;
}
siftUp(i, e)方法如下
private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);
}
siftUpComparable(k, x)方法如下
private void siftUpComparable(int k, E x) {
Comparable super E> key = (Comparable super E>) x;
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (key.compareTo((E) e) >= 0)
break;
queue[k] = e;
k = parent;
}
queue[k] = key;
}
由(key.compareTo((E) e) >= 0)break;
可知。当该元素大于或等于队尾元素时,直接加入该元素,所以可以加入重复的元素
删除则是根据equals方法来查找删除的