您的位置:首页 > 编程语言 > Java开发

深入理解java集合的底层操作

2014-04-19 21:15 671 查看
集合:层次结构:

(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<R> t=new TreeSet(new Comparator<R>()

 {

     @Override

     public int compare(R o1, R o2)

     {

              return o1.count>o2.count?-1:o1.count<o2.count?1:0;              

     }

 });

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<r.count?-1:0;

 }

}

public class Test

{

public static void main(String[] args)

{

    TreeSet<R> t=new 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.ArrayLi
b7b0
st;

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方法来查找删除的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: