Java-集合
集合看作一宗容器,保存一组元素;
对比数组:
1,数组使用时必须指定长度;
2,长度一旦指定,就不能更改
示例:
Person[] pers = new Person[3];
集合示例:
List list = new ArrayLsit(); list.add(new Person()); list.add(new Person()); list.add(new Person());
面向对象都是对象的形式体现,为了方便对对象的存储,数组对对象的存储就出现了弊端,这时候集合就完美的解决了这个问题,(集合就是在数组的基础上进行了封装提供了好用快捷的方法实现了动态把多个对象放引入到集合中)
集合的框架体系:
|----Collection
|----List (可以保存可重复的元素;可以保证插入取出元素顺序的一致性)
|----ArrayList
|----LinkedList
|----Vector
|----Set (不可以保存重复元素;不可以保证插入取出顺序的一致性)
|----HashSet
|----TreeSet
|----Map
|----HashMap
|----HashTable
|----TreeMap
|----Properties
collection接口的特点和使用:
里面保存了一组对象,有的可以重复,有的不可以重复。有的是有序的,有的是无序的。
没有提供直接的实现类,而提供了子接口 List 和 set
常见的方法:
Boolean | add(E,O);添加方法,向集合中添加对象元素 |
Boolean | remove(Object,o);删除集合中的对象元素 |
Boolean | contains(Object,o);查找集合中的对象元素 |
Boolean | addAll(collecton c);批量向集合对象中添加元素 |
int |
size();获取实际元素个数 |
Boolean |
removeAll(conllection c);批量删除集合中的元素 |
Boolean |
isEmpty();判断集合是否为空,如果为空返回true,否则返回false |
迭代器iterator遍历集合元素:
工作原理和特点:
- 当调用iterator遍历集合元素的时候,默认指向集合的最上方;
- 每次调用next()方法进行下移,并且不能下移;
- 一般使用迭代器可以进行读取操作,不能进行删除,若要删除可以使用迭代器本身的方法【remove()方法】;增加不可以,修改只能修改对象的属性,不能修改内存地址;
增 × 不能增加 删 √ 自能使用迭代器自带的remove方法删除 改 √ 只能修改元素对象的属性,地址不能修改 查 √
调用next()方法之前会调用hasnext()方法判断下一个元素是否存在,如果有下一个元素返回true,没有则返回false;
1 public static void main(String[] args) { 2 Collection col = new ArrayList(); 3 col.add(new Book("西游记", 12.0, "吴承恩")); 4 col.add(new Book("水浒", 12.0, "施耐庵")); 5 col.add(new Book("三国", 12.0, "罗贯中")); 6 col.add(new Book("红楼梦", 12.0, "曹雪芹")); 7 //col.add(new Book("西游记", 12.0, "吴承恩")); 8 9 Iterator iterator = col.iterator(); 10 11 while(iterator.hasNext()) { 12 Object next = iterator.next(); 13 System.out.println(next); 14 } 15 16 }
boolean | hasnext();判断下一个对象元素是否存在,存在返回true,不存在返回false。 |
E | next();下一个 |
default void | remove();删除元素对象 |
方式二:使用增强for循环遍历
增强for循环时JDK1.5推出的用来代替iterator迭代器的,主要用于遍历集合和数组,其简化了iterator,但其实本质也是iterator;
因为foreach循环迭代的本质是iterator,所以符合迭代器的特性;如上所示;(迭代过程中的删除建议使用iterator);
LIst接口
特点
1.有序(插入和读取的顺序一致)因为支持索引,索引从0开始;
2.允许重复元素;
常见方法
增 | add(int index,Object element);在指定索引的位置处增加元素 |
删 | remove(int index);根据集合下标索引删除对象元素 |
改 | set(int index,Object element);根据对象索引修改集合元素 |
查 | indexOf(Object element); 根据对象查找 |
获取 | get(int index);根据索引获取对象元素 |
1 @Test 2 public void test1() { 3 List list = new ArrayList(); 4 list.add(100); 5 list.add(200); 6 list.add(200); 7 list.add(300); 8 9 System.out.println(list); 10 list.remove(200); 11 System.out.println(list); 12 }
//会报下标越界错误;
/*
因为add方法是重载的collection的add方法,传入100,200,300属于int类型,程序默认会找同等类型的方法【add(int,index)】
*/
使用list.remove(new Integer(200));
遍历方式
1 public static void main(String[] args) { 2 List list = new ArrayList(); 3 list.add("wwer"); 4 list.add("wwedfr"); 5 list.add("dfwwer"); 6 list.add("wdwwwer"); 7 list.add("wwdfwer"); 8 9 printList3(list); 10 } 11 //方式一: 12 public static void printList1(List list) { 13 Iterator iterator = list.iterator(); 14 while (iterator.hasNext()) { 15 Object object = (Object) iterator.next(); 16 System.out.println(object); 17 } 18 } 19 //方式二 20 public static void printList2(List list) { 21 for (Object object : list) { 22 System.out.println(object); 23 } 24 } 25 //方式三 26 public static void printList3(List list) { 27 for(int i = 0; i<list.size(); i++) { 28 Object object = list.get(i); 29 System.out.println(object); 30 } 31 }
List的实现类
ArrayList 底层:可变数组
1,ArrayList底层维护了一个object[] elementDate的可变数组,在jdk8中初始化容量为0,在降低版本中初始化容量为10;
1 private void ensureCapacityInternal(int minCapacity) { 2 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { 3 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); 4 } 5 6 ensureExplicitCapacity(minCapacity); 7 } 8 9 private void ensureExplicitCapacity(int minCapacity) { 10 modCount++; 11 12 // overflow-conscious code 13 if (minCapacity - elementData.length > 0) 14 grow(minCapacity); 15 }
2,在添加元素时,先进行判断是否需要扩容,如果不需要扩容直接添加元素对象到第一个空位上;
如果是第一次添加直接扩容到容量为10;
如果为其他次添加则直接扩容1.5倍;
1 private void grow(int minCapacity) { 2 // overflow-conscious code 3 int oldCapacity = elementData.length; 4 int newCapacity = oldCapacity + (oldCapacity >> 1); 5 if (newCapacity - minCapacity < 0) 6 newCapacity = minCapacity; 7 if (newCapacity - MAX_ARRAY_SIZE > 0) 8 newCapacity = hugeCapacity(minCapacity); 9 // minCapacity is usually close to size, so this is a win: 10 elementData = Arrays.copyOf(elementData, newCapacity); 11 }
3,进行数组元素的复制;
elementDate = Array.copyOf(elementDate ,newCapycity);
4,将新元素放在elementDate第一个空位上;
LinkedList 底层:双向链表
1,LinkedList底层维护了两个Node节点 first 和 last 节点,每个节点对应了三个属性,分别是 prev ,item ,next上一个元素对象,当前元素对象,下一个元素对象;
1 private static class Node<E> { 2 E item; 3 Node<E> next; 4 Node<E> prev; 5 6 Node(Node<E> prev, E element, Node<E> next) { 7 this.item = element; 8 this.next = next; 9 this.prev = prev; 10 } 11 }
2,当进行添加元素时:
①先将last节点保存在临时变量l中;
②创建一个新的Node节点对象 Node newNode = new Node(l,e,null);将新节点的前一个和后一个都链接上;
③将新节点的引用指向last;last = newNode;
④判断是否为第一次添加
如果时第一次添加,
first = newNode;
不是第一次添加,
l.next=newNode;
void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }
ArrayList和LinkedList的对比:
增删 | 改查 | |
ArrayList 可变数组 | 效率较低:增加和删除必须移动数组元素 | 效率较高:根据索引修改元素对象查找元素对象 |
LinkedList 双向链表 | 效率较高:只需修改next 和prev的引用即可 | 效率较低:链表结构必须从头开始连续调用next进行修改或查找 |
ArrayList和Vector的区别:
底层 | 线程安全同步 | 效率 扩容机制 | |
ArrayList | 可变数组 | 不安全 | 较高 1.5 |
vector | 可变数组 | 安全 | 较低 2 |
set接口
特点:1,无序的,不重复的(至多有一个null)
2,不支持索引,大多set接口的实现类是无序的;
有些实现类比较特殊:比如LinkedHashSet是有序的;
比如TreeSet是排好序的;
常见方法:
没有特有的方法,(Collection)
源码分析:
HashSet集合底层其实是一个Map,
底层维护一个Node[] table,当添加元素的时候,先对改元素进行哈希取值,调用hashCode()方法,通过运算找到对应的位置;
如果当前位置没有值就直接添加,如果有值就调用equals()方法进行比较,如果值相同就直接覆盖,值不同就直接以链表的形式追加节点上;
LinkedHashSet底层是LinkedHashMap,是一个链表+哈希表的结构;
特点:不允许重复;
有序的(插入和取出的顺序是一致的)
如何去重:
实现hashCode和equals方法;
使用:
对象类型和自定义对象类型必须重写hashCode和equals方法;
Map接口
特点
1,内部保存的是kv键值对
2,key不允许重复,value可以重复
3,key可以为null
常见方法
put();
putAll();
remove();
get();
containskey();
containsValue();
size();
clear();
isEmpt();
遍历方式
public class TestMap { public static void main(String[] args) { Map map = new HashMap(); map.put("1", "22"); map.put("2", "22"); map.put("3", "22"); map.put("4", "22"); map.put("5", "22"); map.put("12", "22"); map.put("13", "22"); prinMap2(map); } public static void printMap(Map map) { Set keys = map.keySet(); Iterator iterator = keys.iterator(); while (iterator.hasNext()) { Object key = (Object) iterator.next(); Object value = map.get(key); System.out.println(key+":"+value); } } public static void prinMap2(Map map) { Set entrys = map.entrySet(); for (Object object : entrys) { Map.Entry entry = (Entry) object; Object key = entry.getKey(); Object value = entry.getValue(); System.out.println(key+":"+value); } } }
实现类
HashMap
源码解析
1,HashMap底层解析,底层为哈希表结构
JDK1.8机构为数组+链表+红黑树结构,JDK1.7较低版本为数组+链表