一. Integer与String
1.1 Integer
包装类,就是对根本数据类型的一个包装,赋予一些罕用的办法
比方类型装换等。
int的包装类,应用final润饰类,不可继承。
会主动装箱与主动拆箱。
特地留神:在-128到127之间,保护了一个数组(static初始化,服务器启动就存在。)
比拟值时,如果是这个区间,则默认从数组中拿出值来进行判断。
Integer a = 1;Integer b = 1;Integer c = 128;Integer d = 128;sout(a == b); // truesout(c == d); // false
源码局部
private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} } public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
1.2 String
不可变长字符串。
应用String字符串拼接时,默认调用StringBulider的append办法
String str1 = "hello,";String str2 = "dbc";String str3 = str1 + str2;// 理论: String str3 = (new StringBuilder()).append(str1).append(str2).toString();
String,StringBuilder,StringBuffer的区别
- String: 定长字符串
- StringBuilder: 可变长字符串、线性不平安、效率高
- StringBuffer: 可变长字符串、线性平安、效率低
二. List
有序,可反复
2.1 ArrayList
底层保护了一个数组
会依据存入数据个数和容量,来主动扩容
特点:查问快、增加和删除效率低(和LinkedList相比)。
源码
transient Object[] elementData; // non-private to simplify nested class access private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 带参的一个构造方法 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 boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } // 扩容相干 private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容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); }
2.2 LinkedList
底层保护了一个链表
特点:查问慢、增加和删除快(和ArrayList相比)。
源码
// 链表的节点 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; } }
三. Map
key-value型存储格局
key不可反复
3.1 HashMap
底层是一个哈希表(数组+链表)
key和value能够为null
与HashTable的区别
- HashTable是线性平安的,效率低,而HashMap线性不平安。
- HashTable不允许值(key和value)为null,HashMap的值能够为null
源码
/** * 默认容量(数组长度) */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; /** * 最大容量 */ static final int MAXIMUM_CAPACITY = 1 << 30; /** * Jdk1.8后,数组中某个地位的链表长度为8,并且总元素个数>=64,则将该链表编程红黑树 * 优化查问效率 */ static final int TREEIFY_THRESHOLD = 8; /** * 最小树化容量 * 数组中某个地位的链表长度为8,并且总元素个数>=64,则将该链表编程红黑树 * 优化查问效率 */ static final int MIN_TREEIFY_CAPACITY = 64; /** * 当数据个数低于这个数,将其转换为链表 */ static final int UNTREEIFY_THRESHOLD = 6; /** * 负载因子,增加元素时,当哈希表中的元素个数为:数组长度*负载因子时,会扩容 */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * 根本的哈希bin节点 */ static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; Node(int hash, K key, V value, Node<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } public final K getKey() { return key; } public final V getValue() { return value; } public final String toString() { return key + "=" + value; } public final int hashCode() { return Objects.hashCode(key) ^ Objects.hashCode(value); } public final V setValue(V newValue) { V oldValue = value; value = newValue; return oldValue; } public final boolean equals(Object o) { if (o == this) return true; if (o instanceof Map.Entry) { Map.Entry<?,?> e = (Map.Entry<?,?>)o; if (Objects.equals(key, e.getKey()) && Objects.equals(value, e.getValue())) return true; } return false; } }
四. Set
无序、不可反复
底层保护了一个Map
存值时,将增加的值存为Map的key, 而value就是一个Object
故要获取值,只能获取迭代器来遍历
4.1 HashSet
底层保护了一个HashMap
存值时,存的为Map的key
能够增加null(HashMap的key能够为null)
HashSet如何判断元素是否反复的?
- 先判断hashCode
- 再应用equals判断
如果hashCode的返回值相等 并且 equals返回true,则被认为是雷同的元素
源码
... private transient HashMap<E,Object> map; // Dummy value to associate with an Object in the backing Map // 要与反对映射中的对象关联的伪值 private static final Object PRESENT = new Object(); ... // 构造方法 public HashSet() { map = new HashMap<>(); } ... // 增加办法 public boolean add(E e) { return map.put(e, PRESENT)==null; }
4.2 LinkedHashSet
HashSet的子类
双向链表
4.3 TreeSet
底层保护了一个TreeMap
存值时,存的为Map的key
不能增加null
源码
private transient NavigableMap<E,Object> m; TreeSet(NavigableMap<E,Object> m) { this.m = m; } // 构造方法 public TreeSet() { this(new TreeMap<E,Object>()); } // 增加办法 public boolean add(E e) { return m.put(e, PRESENT)==null; }