JAVA面試題整理-基礎
1、List 和 Set 的區別
共同點:它們都是Collection的子接口
區別:
List:這個接口能夠精準的記錄每一個元素的插入位置(換句話說就是這個接口內容所有元素是按照順序去保存的),使用者可以通過索引的方式去取得某個元素的值,這個跟java中數組有點類似,List中保存的所有數據允許重復。
Set:這個接口無法記錄每一個元素的具體位置,整個集合中所有元素是無序排列的,並且Set存儲數據集合是不允許有重復的元素的。
既然List和Set均為接口,那麽就不能直接實例化,需要借助實現他們接口的子類進行實例化,由此來使用接口中提供的各種方法。
實現List接口的子類中包括:ArrayList,LinkedList和Vector
其中ArrayList這個類是類似數組形式的集合實例化,而LinkedList類則是鏈表形式的實例化,具體的差別在於數據結構上面的不同。
Vector 類非常類似ArrayList,兩者的不同之處在於Vector是同步的方法,在多線程操作的時候可能會拋出ConcurrentModificationException。
實現Set接口的子類中包括:HasSet。
2、HashSet 是如何保證不重復的
根據HashSet.add(E e)的JDK源碼,發現HashSet竟然是借助HashMap來實現的,利用HashMap中Key的唯一性,來保證HashSet中不出現重復值。
當調用add(E e)方法時候,首先會調用Object的hashCode方法判hashCode是否已經存在,如不存在則直接插入元素;
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable { static final long serialVersionUID = -5024744406713321676L; private transient HashMap<E,Object> map;// Dummy value to associate with an Object in the backing Map private 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<>(); } public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); } public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor); } public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); } HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); } public Iterator<E> iterator() { return map.keySet().iterator(); } public int size() { return map.size(); } public boolean isEmpty() { return map.isEmpty(); } public boolean contains(Object o) { return map.containsKey(o); } public boolean add(E e) { return map.put(e, PRESENT)==null; } public boolean remove(Object o) { return map.remove(o)==PRESENT; } public void clear() { map.clear(); } public Object clone() { try { HashSet<E> newSet = (HashSet<E>) super.clone(); newSet.map = (HashMap<E, Object>) map.clone(); return newSet; } catch (CloneNotSupportedException e) { throw new InternalError(); } } private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // Write out any hidden serialization magic s.defaultWriteObject(); // Write out HashMap capacity and load factor s.writeInt(map.capacity()); s.writeFloat(map.loadFactor()); // Write out size s.writeInt(map.size()); // Write out all elements in the proper order. for (E e : map.keySet()) s.writeObject(e); } private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in any hidden serialization magic s.defaultReadObject(); // Read in HashMap capacity and load factor and create backing HashMap int capacity = s.readInt(); float loadFactor = s.readFloat(); map = (((HashSet)this) instanceof LinkedHashSet ? new LinkedHashMap<E,Object>(capacity, loadFactor) : new HashMap<E,Object>(capacity, loadFactor)); // Read in size int size = s.readInt(); // Read in all elements in the proper order. for (int i=0; i<size; i++) { E e = (E) s.readObject(); map.put(e, PRESENT); } } }
/** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for the key, the old * value is replaced. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt>. * (A <tt>null</tt> return can also indicate that the map * previously associated <tt>null</tt> with <tt>key</tt>.) */ public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
3、HashMap 是線程安全的嗎,為什麽不是線程安全的(最好畫圖說明多線程環境下不安全)?
參考:http://www.importnew.com/22011.html
4、HashMap 的擴容過程
5、HashMap 1.7 與 1.8 的 區別,說明 1.8 做了哪些優化,如何優化的?
6、final finally finalize
7、強引用 、軟引用、 弱引用、虛引用
8、Java反射
9、Arrays.sort 實現原理和 Collection 實現原理
10、LinkedHashMap的應用
11、cloneable接口實現原理
12、異常分類以及處理機制
13、wait和sleep的區別
14、數組在內存中如何分配
答案待補充... ...
JAVA面試題整理-基礎