二、add方法
add方法有两个重载,这里只研究最简单的那个。
/* * Adds the specified object at the end of this {@code ArrayList}. * @param obj ect * the object to add. * @return always true */ @Override public boolean add(E object) { object[] a = array; int s = size; if (s == a.length){ object[] newArray = new object[s + (s < (MIN CAPACITY_ INCREMENT / 2) ? MIN CAPACITY INCREMENT : s >> 1)]; System. arraycopy(a, 0, newArray, 0, s); array= a= newArray; } a[s] = object; size = s+1; modCount++; return true; }
1、首先将成员变量array赋值给局部变量a,将成员变量size赋值给局部变量s。
2、判断集合的长度s是否等于数组的长度(如果集合的长度已经等于数组的长度了,说明数组已经满了,该重新分配新数组了),重新分配数组的时候需要计算新分配内存的空间大小,如果当前的长度小于MIN_CAPACITY INCREMENT/2 (这个常量值是12,除以2就是6,也就是如果当前集合长度小于6)则分配12个长度,如果集合长度大于6则分配当前长度s的一半长度。这里面用到了三元运算符和位运算,s >> 1,意思就是将s往右移1位,相当于s=s/2,只不过位运算是效率最高的运算。
3、将新添加的object对象作为数组的a[s]个元素。
4、修改集合长度size为s+1。
5、modCotun+ +,该变量是父类中声明的,用于记录集合修改的次数,记录集合修改的次数是为了防止在用迭代器迭代集合时避免并发修改异常,或者说用于判断是否出现并发修改异常的。
6、return true,这个返回值意义不大,因为一直返回true,除非报了一个运行时异常。
三、remove方法
remove方法有两个重载,我们只研究remove (int index)方法。
/*Removes the object at the specified location from this list. * @param index * the index of the object to remove 。 * areturn the removed object. * @throws IndexOu tofBounds Exception * when {@code location < 0 || location >= size() } */ @Override public E remove (int index) { object[] a = array; int s = size; if (index >= s) { throwIndexOu tOfBounds Exception (index, s); } @SuppressWarnings ("unchecked") E result = (E) a [index] ; System.arraycopy(a, index + 1, a, index, --s -index) ; a[s] = null; // Prevent memory leak size = s modCount++; return result; }
1、先将成员变量array和size赋值给局部变量a和s。
2、判断形参index是否大于等于集合的长度,如果成了则抛出运行时异常
3、获取数组中脚标为index的对象result,该对象作为方法的返回值
4、调用System的arraycopy函数,拷贝原理如下图所示。
System.arraycopy(a, index + 1,a, index, --s - index);
假设index=2,那么要删除的对象如图打叉部分,我们只需要将该数组后面蓝色区域整体往前移动一位位置即可。上面的代码完成就是这个工作。
5.接下来就是很重要的一个工作,因为删除了一个元素,而且集合整体向前移动了一位,因此需要将集合最后一个元索设置为null,否则就可能内存泄露。
6、重新给成员变量array 和size赋值。
7.记录修改次数。
8、返回删除的元素(让用户再看最后一眼)。
四、dear方法
/** * Removes all elements from this {@code ArrayList. leaving it * * ewpty. * @see #isEmpty * @see #size */ Override public void clear() { if (size != 0){ Arrays.fil(array.0, size,null); size = 0; modCount++; } }
4. List 的三个子类的特点
ArrayList底层结构是数组底层查询快,增删慢。
LinkedList底层结构是链表型的,增删快,查询慢。
voctor底层结构是数组 线程安全的,增删慢查询慢。
5. List 和Map、Set 的区别
5.1结构特点
List和Set是存储单列数据的集合,
Map是存储键和值这样的双列数据的集合;
List 中存储的数据是有顺序,并且允许重复; Map中存储的数据是没有顺序的,其键是不能重复的,它的值是可以有重复的,Set 中存储的数据是无序的,且不允许有重复,但元素在集合中的位置由元素的hashcode决定,位置是固定的(Set集合根据hashcode来
进行数据的存储,所以位置是固定的,但是位置不是用户可以控制的,所以对于用户来说set中的元素还是无序的) ;
5.2实现类
List接口有三个实现类(LinkedList:基于链表实现,链表内存是散乱的,每一个元素存储本身内存地址的同时还存储下一个元素的地址。链表增删快,查找慢; ArrayList: 基于数组实现,非线程安全的,效率高,便于索引,但不便于插入删除; Vector:基于数组实现,线程安全的,效率低)。
Map接口有三个实现类(HashMap: 基于hash表的Map接口实现,非线程安全,高效,支持null值和null键; HashTable: 线程安全,低效,不支持null值和null键; LinkedHashMap: 是HashMap的一个子类,保存了记录的插入顺序; SortMap 接口: TreeMap, 能够把它保存的记录根据键排序,默认是键值的升序排序)。
Set接口有两个实现类(HashSet: 底层是由HashMap实现,不允许集合中有重复的值,使用该方式时需要重写equals0和hashCode0方法; LinkedHashSet: 继承与HashSet,同时又基于LinkedHashMap来进行实现,底层使用的是LinkedHashMp)。
5.3区别
List集合中对象按照索引位置排序,可以有重复对象,允许按照对象在集合中的索引位置检索对象,例如通过list.get()方法来获取集合中的元素; Map中的每一个元素包含一个键和一个值,成对出现,键对象不可以重复,值对象可以重复; Set集合中的对象不按照特定的方式排序,并且没有重复对象,但它的实现类能对集合中的对象按照特定的方式排序,例如TreeSet类,可以按照默认顺序,也可以通过实现Java.util.Comparator 接口来自定义排序方式。
6 HashMap 和HashTable有什么区别?
HashMap是线程不安全的,HashMap是一个接口,是Map的一个子接口,是将键映射到值得对象不允许键值重复,允许空键和空值;由于非线程安全,HashMap的效率要较HashTable的效率高一些.
HashTable是线程安全的一个集合,不允许null值作为一个key值或者Value值;
HashTable是sychronize,多个线程访问时不需要自己为它的方法实现同步,而HashMap在被多个线程访问的时候需要自己为它的方法实现同步;
7. Java 中ArrayList和Linkedlist区别?
ArrayList和Vector使用了数组的实现,可以认为ArrayList或者Vector封装了对内部数组的操作,比如向数组中添加,删除,插入新的元素或者数据的扩展和重定向。LinkedList使用了循环双向链表数据结构。与基于数组的ArrayList相比,这是两种截然不同的实现技术,这也决定了它们将适用于完全不同的工作场景。
LinkedList链表由一系列表项连接而成。一个表项总是包含3个部分:元素内容,前驱表和后驱表,如图所示:
在下图展示了一个包含3个元素的LinkedList的各个表项间的连接关系。在JDK的实现中,无论LikedList是否为空,链表内部都有一个header表项,它既表示链表的开始,也表示链表的结尾。表项header的后驱表项便是链表中第一个元素,表项header的前驱表项便是链表中最后一个元素。
8. Map中的key和value可以为null么?
HashMap对象的key. value 值均可为null.
HahTable对象的key. value 值均不可为null,
且两者的的key值均不能重复,若添加key相同的键值对,后面的value会自动覆盖前面的value,但不会报错。
测试代码如下:
public class Test { public static void main (String[] args) { Map<String, String> map = new HashMap<String,String>();// HashMap对象 Map<String, String> tableMap = new Hashtable<String, String>(); //HashTable对象 map.put(null, null) ; System.out.println ("hashMap的[key]和[value ]均可以为null:"+map.get(null)); try { tableMap.put(null,"3"); System.out.println(tableMap.get(null)); } catch (Exception e) { System.out.println(" [ERROR] : hashTable的[key]不能为null") ; } try { tableMap.put ("3",null); System.out.println(tableMap.get ("3")); } catch(Exception e) { System.out.println(" [ERROR] : hashTable的[value]不能为null"); } } }
运行结果: