-
new ArrayList(); 底层new的是什么?
数组 -
凡是数组,一定有类型,请问new出来的数组是什么类型? // 超过10怎么扩容?
Objiect类型 -
既然是数组,必然在内存中占据连续的内存空间,请问初始值为多少?(java8为例)
10(懒加载的方式)
源码中的构造方法:
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
- 当数组元素超过初始内存大小的时候,会扩容机制,请详细介绍一下扩容机制?
扩容的方式:原子的一半 (10–>15)
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
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);
}
-
扩容源码:拷贝方法==>Arrays.CopyOf
-
第二次扩容是多少:15–>22(向下取整)
-
是否线程安全?
不安全,因为add方法为了保证并发性的效率,没有加锁。
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
- 请举例线程不安全的代码。
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
for (int i = 1; i < 50; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,6));
System.out.println(list);
}, String.valueOf(i)).start();
}
}
(1)解决方案一:用Vector
vector中的add源码
/**
* Appends the specified element to the end of this Vector.
*
* @param e element to be appended to this Vector
* @return {@code true} (as specified by {@link Collection#add})
* @since 1.2
*/
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
(2)解决方案二:用Collections 工具类
附带面试题:Collection & Collections 的区别?
List<String> list = Collections.synchronizedList(new ArrayList<String>()); // 方式二,相当于再次包上一层安全方式。
(3)解决方案二:用CopyOnWriteArrayList
List<String> list = new CopyOnWriteArrayList<>(); // 方式三,读写分离的思想。
每次加1,写的时候加锁,读的时候不加锁。
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
- HashSet的底层数据结构是啥?
HashMap
/**
* 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<>();
}
- HashSet中的add方法是仅仅需要一个值,HashMap中的add()方法是需要键值对,不匹配,如何解释?
只关心key,value都是常量PRESENT。
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element <tt>e</tt> to this set if
* this set contains no element <tt>e2</tt> such that
* <tt>(e==null ? e2==null : e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns <tt>false</tt>.
*
* @param e element to be added to this set
* @return <tt>true</tt> if this set did not already contain the specified
* element
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
也是线程不安全的,解决方法用:ConcurrentHashMap
Map<String, String> map = new ConcurrentHashMap<>();