一. 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); // true
sout(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;
}