Java容器类
来源:互联网 发布:决对争锋网络剧资源 编辑:程序博客网 时间:2024/06/06 14:12
@kingpin
2014-06-01 16:29
offer 93
Java容器
set不允许相同值,会将相同集归一
Set:
import java.util.*;public class SimpleCollection{public static void main(String[] args) { Set<Integer> c = new HashSet<Integer>(); for(int i=0;i<10;i++){ c.add(i); } c.add(0); for(Integer i : c){ System.out.println(i); }}}
答案:
0 1 2 3 4 5 6 7 8 9
Collection允许相同值
Collection:
import java.util.*;public class SimpleCollection{public static void main(String[] args) { Collection<Integer> c = new ArrayList<Integer>(); for(int i=0;i<10;i++){ c.add(i); } c.add(0); for(Integer i : c){ System.out.println(i); }}}
答案:
0 1 2 3 4 5 6 7 8 9 0
Collection的method
import java.util.*;public class AddingGroups{public static void main(String[] args) { Collection<Integer> collection = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5)); Integer[] moreInts = {6,7,8,9,10}; collection.addAll(Arrays.asList(6,7,8,9,10)); System.out.println(collection.toString()); Collections.addAll(collection,11,12,13,14,15); Collections.addAll(collection,moreInts); System.out.println(collection.toString());}}
List和set都属于Collection
import java.util.*;public class ConstructorT{static String[] FaMovic = {"Shawshank Redemption","Dark Knight Rises","Avengers"};static int number = FaMovic.length;static int index = 0;public static String next(){ if(index < number){ return FaMovic[index]; } else{ index =0; return FaMovic[index]; }}public static void main(String[] args) { Collection<String> arrListObj = new ArrayList<String>(); Collection<String> linkListObj = new LinkedList<String> (); Collection<String> hashSetObj = new HashSet<String> (); Collection<String> linkedHashsetObj = new LinkedHashSet<String> (); Collection<String> treeSetObj = new TreeSet<String> (); for(int i=0;i<9;i++){ arrListObj.add(ConstructorT.next()); linkListObj.add(ConstructorT.next()); hashSetObj.add(ConstructorT.next()); linkedHashsetObj.add(ConstructorT.next()); treeSetObj.add(ConstructorT.next()); index++; } System.out.println("arrListObj: "+arrListObj); System.out.println("linkListObj: "+linkListObj); System.out.println("hashSetObj: "+hashSetObj); System.out.println("linkedHashsetObj: "+linkedHashsetObj); System.out.println("treeSetObj: "+treeSetObj);}}
所有的linked都是按顺序输入,tree是按字典顺序,hash只在乎速度,不在乎顺序
List Integer Arrays.asList(a)
import java.util.*;public class ListFeaInteger{public static void main(String[] args) { Random rand = new Random(47); Integer[] a = {1,2,3,4,5,6,7}; List<Integer> inte = new ArrayList<Integer>(Arrays.asList(a)); System.out.println("1: "+inte); inte.add(8); System.out.println("2: "+inte); System.out.println("3: "+inte.contains(8) ); inte.remove(new Integer(8)); int temp = inte.get(2); System.out.println("4: "+temp +" "+inte.indexOf(temp)); inte.add(4,new Integer(100)); System.out.println("5: "+inte); List<Integer> sub = inte.subList(1,4); System.out.println("subList: "+sub); System.out.println("6: "+inte.containsAll(sub)); Collections.sort(sub); System.out.println("sort subList: "+sub); Collections.shuffle(sub,rand); System.out.println("shuffle subList: "+sub); } }
List 源码学习分析之:ArrayList
import java.util.*;import java.util.ArrayList;public class subL{public static void main(String[] args) { // dog[] arr = { }; List<Dog> arrListDog = Arrays.asList(new Dog(1), new Dog(2), new Dog(3)); List<Dog> subLDog = arrListDog.subList(0,2); System.out.println(subLDog); if(arrListDog.retainAll(subLDog)){ System.out.println(true); } System.out.println(arrListDog);}}class Dog{ int age=0; Dog(){age++;} Dog(int age){ this.age = age; } public String toString(){ return "dog : "+age; }}
会抛出错误,java.lang.UnsupportedOperationException
进入源码分析
首先Arrays.asList() return 的是:
public static <T> List<T> asList(T... a) {return new ArrayList<T>(a);}
ArrayList 泛型ArrayList
而List中是带有retainAll 和 removeAll的
* Removes from this list all of its elements that are contained in the * specified collection (optional operation). * * @param c collection containing elements to be removed from this list * @return <tt>true</tt> if this list changed as a result of the call * @throws UnsupportedOperationException if the <tt>removeAll</tt> operation * is not supported by this list * @throws ClassCastException if the class of an element of this list * is incompatible with the specified collection (optional) * @throws NullPointerException if this list contains a null element and the * specified collection does not permit null elements (optional), * or if the specified collection is null * @see #remove(Object) * @see #contains(Object) */boolean removeAll(Collection<?> c);
但是从这个注释中哦我们可以看到 @throws UnsupportedOperationException if the removeAll operation 如果没有这个的话会抛出错误
但是 从集成关系中知道
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
ArrayList是继承了List
但是在ArrayList中是没有removeAll和 retainAll
相当奇怪,现在暂时上不了网,再说吧。这不是违反了Java的实现规则吗?
第二个疑问:
import java.util.*;public class subL{public static void main(String[] args) { // dog[] arr = { };// LinkedList arrLinkedList = (LinkedList)Arrays.asList(new Dog(1), new Dog(2), new Dog(3)); ArrayList a = new ArrayList(); LinkedList b= new LinkedList(); List<Dog> arrListDog = Arrays.asList(new Dog(1), new Dog(2), new Dog(3)); List<Dog> subLDog = arrListDog.subList(0,2); System.out.println(subLDog); for(Dog temdog:subLDog) arrListDog.remove(temdog); System.out.println(arrListDog);}
}
class Dog{ int age=0; Dog(){age++;} Dog(int age){ this.age = age; } public String toString(){ return "dog : "+age; }}
这个情况和刚刚的一样,都是说不支持remove,但是这里的ArrayList有remove方法:
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;}
也有 removeAll,但是就是报错:错误信息如下:
Exception in thread "main" java.lang.UnsupportedOperationExceptionat java.util.AbstractList.remove(Unknown Source)at java.util.AbstractList$Itr.remove(Unknown Source)at java.util.AbstractCollection.removeAll(Unknown Source)at subL.main(subL.java:13)
不知道怎么回事。跳过。
各种Collection派生类的应用:
import java.util.*;public class CrossContainerIteration {public static void display(Iterator<Dog> it){ while(it.hasNext()){ Dog dog = it.next(); System.out.print(dog+" "); } System.out.println();}public static void main(String[] args){ List<Dog> dogs = Arrays.<Dog>asList(new Dog(19),new Dog(21),new Dog(31),new Dog(44),new Dog(6),new Dog(10)); // ArrayList<Dog> dogsLs = new ArrayList<Dog>(dogs); LinkedList<Dog> dogsll = new LinkedList<Dog>(dogs); LinkedHashSet<Dog> dogsLHS = new LinkedHashSet<Dog>(dogsll); HashSet<Dog> dogsHs = new HashSet<Dog>(dogs); TreeSet<Dog> dogsTs = new TreeSet<Dog>(dogs); System.out.println("ArrayList<Dog>"); display(dogs.iterator()); System.out.println("LinkedList<Dog>"); display(dogsll.iterator()); System.out.println("LinkedHashSet<Dog>"); display(dogsLHS.iterator()); System.out.println("HashSet<Dog>"); display(dogsHs.iterator()); System.out.println("TreeSet<Dog>"); display(dogsTs.iterator());}}class Dog implements Comparable<Dog>{int age=0;Dog(){age++;}Dog(int age){ this.age = age;}public String toString(){ return "dog : "+age;}//必须实现compareTo才能被TreeSet使用public int compareTo(Dog dog){ if(this.age > dog.age){ return 1; } else{ return -1; }}}
其中自定义的类必须实现Comparable接口并且实现compareTo才能使用在TreeSet中
Collection类型总结:
LinkedList, ArrayList, HashSet , LinkedHashSet , TreeSet
分析
ArrayList
private static final Object[] EMPTY_ELEMENTDATA = {};private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); //从这句我们可以看出来 newCapacity 是 oldCapacity的1.5倍。 //结合上下文,最小的增长值也是1.5倍 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); // 根据情况来看,elementData才是放元素的,但是他是transitent就是说在传输的时候不会传输这个。}private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;}public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; //从这段源码来看,ArrayList可以有null值 } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1;}//看这段挺有感觉的,原来modCount每次在修改的时候都改变是为了在writeObject的时候能同步,如果在writeObject的时候不同步就抛出一个错误。因此,ArrayList线程不安全。private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{ // Write out element count, and any hidden stuff int expectedModCount = modCount; s.defaultWriteObject(); // Write out size as capacity for behavioural compatibility with clone() s.writeInt(size); // Write out all elements in the proper order. for (int i=0; i<size; i++) { s.writeObject(elementData[i]); } if (modCount != expectedModCount) { throw new ConcurrentModificationException(); }}
小疑问一个:既然此前的 elementData是transient的,为何在writeObject的时候又能使用它?
对一个小问题有兴趣:ArrayList里面的 iterator()返回的是ArrayList里面的一个内部类Itr,然后:
private class Itr implements Iterator<E> { /** * Index of element to be returned by subsequent call to next. */ int cursor = 0; /** * Index of element returned by most recent call to next or * previous. Reset to -1 if this element is deleted by a call * to remove. */ int lastRet = -1; /** * The modCount value that the iterator believes that the backing * List should have. If this expectation is violated, the iterator * has detected concurrent modification. */ int expectedModCount = modCount; public boolean hasNext() { return cursor != size(); } public E next() { checkForComodification(); try { int i = cursor; E next = get(i); lastRet = i; cursor = i + 1; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { AbstractList.this.remove(lastRet); if (lastRet < cursor) cursor--; lastRet = -1; //这里指的注意,因为lastRet本来标记的在AbstractList.this.remove(lastRet)中被删除了,所以cursor--指向删除的那个(正常情况下),然后lastRet没地方指了只能回到-1,这种情况下如果再进行 remove,那么AbstractList.this.remove(lastRet)是不会成功的,是不是这样,我们应该试试。 expectedModCount = modCount; } catch (IndexOutOfBoundsException e) { throw new ConcurrentModificationException(); } }
有三种方案删除ArrayList里面的元素,请记着:
import java.util.*;public class ArrayListItr {public static void main(String[] args){ // Integer[] a = ; List<Integer> arr = new ArrayList(Arrays.asList(new Integer[]{1,2,3,4})); arr.add(new Integer(1)); //第三种方案 ListIterator<Integer> arrListItr = arr.listIterator(arr.size()); while(arrListItr.hasPrevious()){ if((new Integer(1).equals(arrListItr.previous()))){ arrListItr.remove(); } } System.out.println(arr); //第一种方案// Iterator<Integer> it = arr.iterator();// while(it.hasNext()){// if ((new Integer(1)).equals(it.next())){// it.remove();// }// }// System.out.println(arr); //第二种方案 // for (int i = 0; i < arr.size(); i++) { // if ((new Integer(1)).equals(arr.get(i))) { // arr.remove(i); // i--; // } // } // System.out.println(arr); }}
前文中出现了 由 Arrays.asList引发的错误
现在来使用 listIterator
ListIterator的add方法和Iterator的remove方案注意点一样,将lastRet=1,都是必须 通过 next或者previous将 里面的 lastret值改变,才能继续下一次add和remove
public void add(E e) { checkForComodification(); try { int i = cursor; ArrayList.this.add(i, e); cursor = i + 1; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } }
LinkedList
从变量定义的角度看LinkedList就和ArrayList大相径庭
transient int size = 0;/** * Pointer to first node. * Invariant: (first == null && last == null) || * (first.prev == null && first.item != null) */transient Node<E> first;/** * Pointer to last node. * Invariant: (first == null && last == null) || * (last.next == null && last.item != null) */transient Node<E> last;
存储数据的量原来一直都是 transient,回头不得不好好理解一下transient
我们可以看看Node 的定义:
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; }}
静态内部类,没有空的构造函数
构造函数:
public LinkedList() {}/** * Constructs a list containing the elements of the specified * collection, in the order they are returned by the collection's * iterator. * * @param c the collection whose elements are to be placed into this list * @throws NullPointerException if the specified collection is null */public LinkedList(Collection<? extends E> c) { this(); addAll(c);}
我们来看看第二个使用Collection的构造函数里面的addAll的内容:
//LinkedList是双向链表public boolean addAll(int index, Collection<? extends E> c) { checkPositionIndex(index); Object[] a = c.toArray(); int numNew = a.length; if (numNew == 0) return false; Node<E> pred, succ; if (index == size) { succ = null; pred = last; } else { //这个是当前的,pred是前一个 succ = node(index); pred = succ.prev; } for (Object o : a) { @SuppressWarnings("unchecked") E e = (E) o; Node<E> newNode = new Node<>(pred, e, null); if (pred == null) first = newNode; else pred.next = newNode; pred = newNode; } if (succ == null) { last = pred; } else { pred.next = succ; succ.prev = pred; } size += numNew; modCount++; return true;}//这个函数写得很好,小疑问就是 size>>1不就改变了 size的值了吗?Node<E> node(int index) { // assert isElementIndex(index); if (index < (size >> 1)) { Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; }}
这里有个不懂得method
/** * Unlinks non-null first node f. */private E unlinkFirst(Node<E> f) { // assert f == first && f != null; final E element = f.item; final Node<E> next = f.next; f.item = null; f.next = null; // help GC first = next; if (next == null) last = null; else next.prev = null; size--; modCount++; return element;}/** * Unlinks non-null last node l. */private E unlinkLast(Node<E> l) { // assert l == last && l != null; final E element = l.item; final Node<E> prev = l.prev; l.item = null; l.prev = null; // help GC last = prev; if (prev == null) first = null; else prev.next = null; size--; modCount++; return element;}
如果加入的不是头一个,而是第二个,那么释放的就应该是前二个,试一下:
试过后发觉,原来这两个是private,就是只是被内部调用
public boolean remove(Object o) { if (o == null) { for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) { unlink(x); return true; } } } else { for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) { unlink(x); return true; } } } return false;}
从remove的源码可以看出来,LinkedList其实是允许null值
public int indexOf(Object o) { int index = 0; if (o == null) { for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) return index; index++; } } else { for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) return index; index++; } } return -1;}
在indexOf method中我比较感兴趣的是,空的Object使用equals会返回什么?空的Object equals(null), 试一下:
Object a = new Object();
// Object a = null;
Object b = null;
a.equals(b); System.out.println(a.equals(b));
输出是 false,a != null, b==null, a.equals(b) 是 false,但是如果 a==null,要使用 a.equals() 会报错。
LinkedList还实现了 stack 功能和 deque 接口,能很使用 pollFirst pollLast,push,pop,offerFirst,offerLast等等。
真方便,直接当 stack和deque用。
ArrayList就没有这个功能,但是 LinkedList需要的遍历开销也不小
需要注意的是,LinkedList类本身没有 重写Iterator(),ArrayList重写了Iterator(),所以LinkedList使用的Iterator属于AbstractSequentialList也属于AbstractList源头是AbstractCollection,但是在AbstractCollection中iterator()是个abstract method,所以如果要使用iterator来遍历LinkedList不如直接使用 ListIterator。
同样 在使用 ListIterator的remove或者add前也必须使用 next或者previous
import java.util.*;public class lrnLinkedlist {public static void main(String[] args){ List<Dog> lList= new LinkedList<Dog>(Arrays.asList(new Dog(1),new Dog(2),new Dog(10))); LinkedList<Dog> LLList = (LinkedList<Dog>)lList;// Iterator<Dog> it = LLList.iterator();// ListIterator<Dog> it = LLList.listIterator();// // it.next();// it.remove();// it.remove(); Dog dog1= new Dog(20); List<Dog> temp = Arrays.asList(dog1); LLList.push(dog1); LLList.push(new Dog(11)); System.out.println(LLList); LLList.offerFirst(new Dog(14)); System.out.println(LLList); LLList.pop(); System.out.println(LLList.containsAll(temp)); System.out.println(LLList.contains(dog1)); System.out.println(LLList);}}
到这里,LinkedList的基本使用就这样了。
HashSet
欢迎进入HashSet的领域:
看到 HashSet的constructor就震惊了,是HashMap
private transient HashMap<E,Object> map;// Dummy value to associate with an Object in the backing Mapprivate static final Object PRESENT = new Object();/** * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has * default initial capacity (16) and load factor (0.75). */public HashSet() { map = new HashMap<>();}/** * Constructs a new set containing the elements in the specified * collection. The <tt>HashMap</tt> is created with default load factor * (0.75) and an initial capacity sufficient to contain the elements in * the specified collection. * * @param c the collection whose elements are to be placed into this set * @throws NullPointerException if the specified collection is null */public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c);}/** * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has * the specified initial capacity and the specified load factor. * * @param initialCapacity the initial capacity of the hash map * @param loadFactor the load factor of the hash map * @throws IllegalArgumentException if the initial capacity is less * than zero, or if the load factor is nonpositive */public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor);}/** * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has * the specified initial capacity and default load factor (0.75). * * @param initialCapacity the initial capacity of the hash table * @throws IllegalArgumentException if the initial capacity is less * than zero */public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity);}/** * Constructs a new, empty linked hash set. (This package private * constructor is only used by LinkedHashSet.) The backing * HashMap instance is a LinkedHashMap with the specified initial * capacity and the specified load factor. * * @param initialCapacity the initial capacity of the hash map * @param loadFactor the load factor of the hash map * @param dummy ignored (distinguishes this * constructor from other int, float constructor.) * @throws IllegalArgumentException if the initial capacity is less * than zero, or if the load factor is nonpositive */HashSet(int initialCapacity, float loadFactor, boolean dummy) {// 这个boolean dummy 是用来被LinkedHashSet使用,只是一个生产呢过LinkedHashMap的标识 map = new LinkedHashMap<>(initialCapacity, loadFactor);}
在下面的所有的add,set之类的也是调用HashMap,看来必须先看HashMap
public boolean add(E e) { return map.put(e, PRESENT)==null;}
原来PRESENT这样用。
HashSet是HashMap里面的key集
有contains,但是不知道有没有indexOf
LinkedHashSet
LinkedHashSet extends HashSet 所有的操作都使用了LinkedHashMap,因此,构造函数有四个
/** * Constructs a new, empty linked hash set with the specified initial * capacity and load factor. * * @param initialCapacity the initial capacity of the linked hash set * @param loadFactor the load factor of the linked hash set * @throws IllegalArgumentException if the initial capacity is less * than zero, or if the load factor is nonpositive */public LinkedHashSet(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor, true);}/** * Constructs a new, empty linked hash set with the specified initial * capacity and the default load factor (0.75). * * @param initialCapacity the initial capacity of the LinkedHashSet * @throws IllegalArgumentException if the initial capacity is less * than zero */public LinkedHashSet(int initialCapacity) { super(initialCapacity, .75f, true);}/** * Constructs a new, empty linked hash set with the default initial * capacity (16) and load factor (0.75). */public LinkedHashSet() { super(16, .75f, true);}/** * Constructs a new linked hash set with the same elements as the * specified collection. The linked hash set is created with an initial * capacity sufficient to hold the elements in the specified collection * and the default load factor (0.75). * * @param c the collection whose elements are to be placed into * this set * @throws NullPointerException if the specified collection is null */public LinkedHashSet(Collection<? extends E> c) { super(Math.max(2*c.size(), 11), .75f, true); addAll(c);}
TreeSet
欢迎来到TreeSet的世界
一个路数的东西
/** * The backing map. */private transient NavigableMap<E,Object> m;// Dummy value to associate with an Object in the backing Mapprivate static final Object PRESENT = new Object();
NavigableMap
就是说,大概是懂了Map就能把set搞掂。
同时实验证明,Treeset是可以放入相同值,也就是TreeMap的key有相同值。但是Treeset不能放入null,就是TreeMap的key不能为空。大概是要比较所以不能为空。TreeSet 和 TreeMap是如此。TreeSet能够实现相同值,这也说明NavigableMap和HashMap的实现不同, HashMap的内部实现是决定它不能有同一个元素多次出现的原因,看来HashMap的内部结构才是容器的重点。
HashSet 和 LinkedHashSet 都可以为null或者相同值,但是相同值只能出现一次,就是同一个对象放入HashSet和LinkedHashSet中只能存入一次。
但是LinkedList和ArrayList无论是相同值还是null都能够接受。和HashSet,LinkedHashSet不同的是,相同值可以重复出现,在LinkedList和ArrayList的内部实现中,不难理解这个。
欢迎来到HashMap的世界
居然一路写下来,来到了以前载跟头的地方。加油吧
/** * Constructs an empty <tt>HashMap</tt> with the specified initial * capacity and load factor. * * @param initialCapacity the initial capacity * @param loadFactor the load factor * @throws IllegalArgumentException if the initial capacity is negative * or the load factor is nonpositive */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; threshold = initialCapacity; init();}/** * Constructs an empty <tt>HashMap</tt> with the specified initial * capacity and the default load factor (0.75). * * @param initialCapacity the initial capacity. * @throws IllegalArgumentException if the initial capacity is negative. */public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR);}/** * Constructs an empty <tt>HashMap</tt> with the default initial capacity * (16) and the default load factor (0.75). */public HashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);}/** * Constructs a new <tt>HashMap</tt> with the same mappings as the * specified <tt>Map</tt>. The <tt>HashMap</tt> is created with * default load factor (0.75) and an initial capacity sufficient to * hold the mappings in the specified <tt>Map</tt>. * * @param m the map whose mappings are to be placed in this map * @throws NullPointerException if the specified map is null */public HashMap(Map<? extends K, ? extends V> m) { this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); inflateTable(threshold); putAllForCreate(m);}
HashMap有四个constructor,float的参数是用来存loadFactor,int 就是 HashMap的初始化容量,下面的还有很多,先放下都不想想了。跑去看Linux。
回到HashMap, 开始吧:
初次在linux平台上写作,感觉还不赖
private static int roundUpToPowerOf2(int number) { // assert number >= 0 : "number must be non-negative"; return number >= MAXIMUM_CAPACITY ? MAXIMUM_CAPACITY : (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1;}
这段代码是什么意思呢?三目运算符是 右结合性,等价于
private static int roundUpToPowerOf2(int number) { // assert number >= 0 : "number must be non-negative"; return number >= MAXIMUM_CAPACITY ? MAXIMUM_CAPACITY :( (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1);}
当 number 大于1 , number减1 ,最低位为0,左移1位,最低二位为0,那么,number,还是不明白。看来要写测试代码了
Integer 中的 higeestOnebit的源码如下:
/** * Returns an {@code int} value with at most a single one-bit, in the * position of the highest-order ("leftmost") one-bit in the specified * {@code int} value. Returns zero if the specified value has no * one-bits in its two's complement binary representation, that is, if it * is equal to zero. * * @return an {@code int} value with a single one-bit, in the position * of the highest-order one-bit in the specified value, or zero if * the specified value is itself equal to zero. * @since 1.5 */public static int highestOneBit(int i) { // HD, Figure 3-1 i |= (i >> 1); i |= (i >> 2); i |= (i >> 4); i |= (i >> 8); i |= (i >> 16); return i - (i >>> 1);}
这是取出最左段的节奏。
HashMap内部是一个Entry[] ,
这里我们来看看为什么HashMap的null只能有一个:
public V get(Object key) { if (key == null) return getForNullKey(); Entry<K,V> entry = getEntry(key); return null == entry ? null : entry.getValue();}private V getForNullKey() { if (size == 0) { return null; } for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) return e.value; } return null;}
可以看出 当e.key==null 的时候直接return,从侧面说明e.key==null只有一个,但是,具体还是要到add method才能知道
Entry 节点和 LinkedList里面的 Node相当相似
public final boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry)o; Object k1 = getKey(); Object k2 = e.getKey(); if (k1 == k2 || (k1 != null && k1.equals(k2))) { Object v1 = getValue(); Object v2 = e.getValue(); if (v1 == v2 || (v1 != null && v1.equals(v2))) return true; } return false; }
从这里可以看出来,当传进来的是 Map.Entry而且 他们的key和alue分别都是相同的,从hashcode或者内存地址上是相同的,这里应该考虑的是alue或者key是String的情况。
HashMap的源码真是又多又难懂,不管了,先试试怎么用:
由于 Arrays也是个很重要的类,所以现在先来分析Arrays:主要的函数有
sort , binarySearch, equals, fill(填充),copyOf,copyOfRange, asList(重点),hashCode(各种类型的hashCode差别还是挺大),deepHashCode(Object a[]),deepEquals(Object[] a1, Object[] a2)(每个都要相同,才返回true),toString, deepToString,
至于toString,deepToString 和 equals deepEquals一个尿性
int[] a1 = {1,2,3,4,5}; int[] a2 = {6,7,8,9,10}; int[] b1 = {1,2,3,4,5}; int[] b2 = {6,7,8,9,10}; Object[] o1 = {a1,a2}; System.out.println(Arrays.toString(o1)); System.out.println(Arrays.deepToString(o1));
输出:
[[I@e69696, [I@a88bc2]
[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
下面研究下 equals和deepEquals的区别:
equals
public static boolean equals(Object[] a, Object[] a2) { if (a==a2) return true; if (a==null || a2==null) return false; int length = a.length; if (a2.length != length) return false; for (int i=0; i<length; i++) { Object o1 = a[i]; Object o2 = a2[i]; if (!(o1==null ? o2==null : o1.equals(o2))) return false; } return true;}
deepEquals
public static boolean deepEquals(Object[] a1, Object[] a2) { if (a1 == a2) return true; if (a1 == null || a2==null) return false; int length = a1.length; if (a2.length != length) return false; for (int i = 0; i < length; i++) { Object e1 = a1[i]; Object e2 = a2[i]; //这一步,如果 e1 和 e2 都是null 就可以,e1!=e2 但是 e1.equals(e2)成立的大概只有String(真的如此,也许Integer也是?试一试),就是说对String Integer, Double, Long 这些Wraper类也是如此。在上面的普通equals中只是需要== 或者equals成立一个就可以了,但是这里,要求他们指向同一个对象。相当复杂。 if (e1 == e2) continue; if (e1 == null) return false; // Figure out whether the two elements are equal boolean eq = deepEquals0(e1, e2); if (!eq) return false; } return true;}static boolean deepEquals0(Object e1, Object e2) { assert e1 != null; boolean eq; if (e1 instanceof Object[] && e2 instanceof Object[]) eq = deepEquals ((Object[]) e1, (Object[]) e2); else if (e1 instanceof byte[] && e2 instanceof byte[]) eq = equals((byte[]) e1, (byte[]) e2); else if (e1 instanceof short[] && e2 instanceof short[]) eq = equals((short[]) e1, (short[]) e2); else if (e1 instanceof int[] && e2 instanceof int[]) eq = equals((int[]) e1, (int[]) e2); else if (e1 instanceof long[] && e2 instanceof long[]) eq = equals((long[]) e1, (long[]) e2); else if (e1 instanceof char[] && e2 instanceof char[]) eq = equals((char[]) e1, (char[]) e2); else if (e1 instanceof float[] && e2 instanceof float[]) eq = equals((float[]) e1, (float[]) e2); else if (e1 instanceof double[] && e2 instanceof double[]) eq = equals((double[]) e1, (double[]) e2); else if (e1 instanceof boolean[] && e2 instanceof boolean[]) eq = equals((boolean[]) e1, (boolean[]) e2); else eq = e1.equals(e2); return eq;}
testInteger.java (试一试Integer.equals的效果)
import java.util.*;public class testInteger {public static void main(String[] args) { Integer abc = new Integer(10); Integer aaa = new Integer(10);// Integer abc = 130;// Integer aaa = 130; System.out.println(abc==aaa); System.out.println(abc.equals(aaa));}}
答案:false,true, 证明了 == 比的是地址,equals比的是hashCode。和String一样.
以下代码可以说明 equals 和 deepEquals之间的区别:
import java.util.*;public class testInteger {public static void main(String[] args) {// Integer abc = new Integer(10);// Integer aaa = new Integer(10); int[] a1 = {1,2,3,4,5}; int[] a2 = {6,7,8,9,10}; int[] b1 = {1,2,3,4,5}; int[] b2 = {6,7,8,9,10}; Object[] o1 = {a1,a2}; Object[] o2 = {b1,b2}; System.out.println(a1.equals(b1)); System.out.println(Arrays.equals(o1,o2)); System.out.println(Arrays.deepEquals(o1, o2));// Integer abc = 130;// Integer aaa = 130;// System.out.println(abc==aaa);// System.out.println(abc.equals(aaa));}}
答案: flase, false, true
copyOf里面的一个method
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy;}
使用了 Array, 这是反射机制里面的内容:
一直往下面看,最会回到一个native method,至于System.arraycopy也是native method
看完了 Arrays后发觉,构建 还是没有办法构建HashMap,怎么办?
HashMap的键唯一,HashSet也是唯一,HashMap的键的值允许null.
import java.util.*;public class subL{ public static void main(String[] args) { HashMap hm = new HashMap(DogCollection.getDogMap()); hm.put(null,new Dog(11)); hm.put(null,null); hm.remove(null); System.out.println(hm.get("10")); System.out.println(hm.containsValue(DogCollection.getDog1())); hm.put("3", new Dog(4)); Map ma = (Map)hm.clone(); System.out.println(ma); System.out.println(hm.size()); System.out.println(hm); System.out.println(hm.keySet()); System.out.println(hm.values()); System.out.println(hm); System.out.println(hm.entrySet());}}
尽管HashMap的内部实现非常复杂,但是用起来还好,不知道有木有什么陷阱。
对于HashMap的 initialCapacity 和 loadFactor 能正确配置,对提高性能有所影响
下面是 LinkedHashMap
LinkedHashMap不像HashMap , HashMap是使用 Entry[] table 来存数据。
LinkedHashMap使用了Entry Header,accessOrder
//给我20分钟 //说好的 20 分钟用了 60分钟,下次只能给你6分钟。
LinkedHashMap有5个构造器:
前四个和HashMap一样,最后一个是 加了个accessOrder
accessOrder=true指的是访问顺序
关于HashMap里面的负载因子
利用LinkedHashMap实现的 LRU缓存:
import java.util.*;public class subL{ public static void main(String[] args) { LinkedHashMap hm = new MyLinkedHashMap(16,0.75f,true); hm.putAll(DogCollection.getDogMap()); System.out.println(hm); System.out.println(hm.get("5")); System.out.println(hm); hm.put("100", new Dog(100)); System.out.println(hm);}}class MyLinkedHashMap extends LinkedHashMap{public MyLinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { super(initialCapacity,loadFactor,accessOrder);}private static final int MAX_ENTRIES = 12;protected boolean removeEldestEntry(Map.Entry eldest){ return size()>MAX_ENTRIES;}}
Java容器类的学习暂时到这里。
@kingpin
2014-06-01 16:29
- Java容器类学习心得
- Java容器类学习心得
- java容器类
- java容器类
- java容器类
- Java容器类
- Java容器类--Collection
- Java容器类学习
- java 容器类 小结
- java容器类
- JAVA 容器类
- java容器类(1)
- java容器类(2)
- java容器类(3)
- java中的容器类
- JAVA容器类解析
- Java中的容器类
- Java中的容器类
- 大三上学期,图形编程基础
- python类方法和静态方法
- 设计模式(17)-行为型模式-Moderator模式
- python django 与数据库的交互
- 【数据库】sql2008卸载和默认实例的删除
- Java容器类
- UIPopoverController
- Linux系统root密码修改
- java多线程同步工具之CountDownlatch
- python连接MySQL connect函数的参数说明
- 2014-06-01工作周报-耿田义
- 七古·夏泳小梅沙
- 设计模式(18)-行为型模式-MEMENTO模式
- JSON for java入门总结