1 容器的基本概念
图解
- List有序可重复
- Set无序不可重复,相同的会被覆盖
- Map键值对,通过一个对象找另一个对象
容器的概念
在Java当中,如果有一个类专门用来存放其它类的对象,这个类就叫做容器,或者就叫做集合,集合就是将若干性质相同或相近的类对象组合在一起而形成的一个整体
容器和数组的区别
- 数组的容量是有限制的,而Collection库没有这样的限制,它的容量是可以自动调节的
2 collection接口
- collection是容器的根接口
- 定义了一些规则,这时候就体现了接口的意义
- 下面举出几个常用的方法,这些方法在其子类中都是拥有的
Collection<String> collection = new ArrayList<>();
// 添加一个元素
collection.add("zhaodi1");
collection.add("zhaodi2");
// 集合的大小
System.out.println(collection.size());
//集合是否为空
System.out.println(collection.isEmpty());
// 集合是否包含某个对象
System.out.println(collection.contains("zhaodi"));
// 集合转化成数组
Object object[]=collection.toArray();
System.out.println(Arrays.toString(object));
// 从容器移除这个对象,记住这是移除不是删除
collection.remove("zhaodi1");
System.out.println(collection.size());
3 List接口
ArrayList,LinkedList,Vector
- ArrayList 查询速度快,修改,删除,插入速度很慢,因为底层是数组实现的
- LinkedList 查询速度慢,修改,删除,插入速度很快,因为底层是链表
- Vector 线程安全,效率低
- 可以重复
package com.zhao.collection;
import java.util.List;
import java.util.ArrayList;
import java.util.Date;
/**
* ArrayList 查询速度快,修改,删除,插入速度很慢,因为底层是数组实现的
* LinkedList 查询速度慢,修改,删除,插入速度很快,因为底层是链表
* Vector 线程安全,效率低
* @author zhao_di
*
*/
public class Demo01 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("zhaodi");
list.add("is");
list.add("good");
list.add("man");
list.add(new Date());
list.remove("is");
//清空容器
list.clear();
list.add(1234);//1234被自动装箱成Integer!!!!
System.out.println(list.get(1));//is
System.out.println(list.size());//
// 获取元素,返回值是Object
Object string = list.get(0);
// 某个位置设置一个元素
list.set(list.size()-1, "dd");
}
}
自己实现ArrayList,LinkedList
ArrayList
package com.demo.utils.Test_Collection;
/**
* @author zhaod
* @description
* 模仿实现ArrayList,底层是数组实现的,具体的操作依赖System.copy这个方法
* 1、add 新增一个元素
* 2、get 获取指定index的元素
* 3、remove 更具index删除元素
* 4、set 指定index出赋值
*
* @date 2018/5/9 11:15
*/
public class ArrayListDemo {
/**
* 容器的大小
*/
private int size;
/**
* 数组元素
*/
private Object[] elementData;
public ArrayListDemo() {
this(10);
}
public ArrayListDemo(int initialCapacity) {
if (initialCapacity > 0) {
elementData = new Object[initialCapacity];
}
}
/**
* 容器的大小
*
* @return
*/
public int size() {
return size;
}
/**
* 添加元素
*
* @param object
* @return
*/
public boolean add(Object object) {
if (size >= elementData.length) {
Object[] newElementDatas = new Object[size * 2];
System.arraycopy(elementData, 0, newElementDatas, 0, elementData.length);
elementData = newElementDatas;
}
elementData[size] = object;
size++;
return true;
}
/**
* 获取元素
*
* @param index 索引,从0开始
* @return
*/
public Object get(int index) {
if (index >= size || index < 0) {
throw new RuntimeException("index is wrong");
}
return elementData[index];
}
/**
* 删除元素
*
* @param index
* @return
*/
public Object remove(int index) {
if (index >= size || index < 0) {
throw new RuntimeException("index is wrong");
}
System.arraycopy(elementData, index + 1, elementData, index, size - index - 1);
// gc 回收垃圾
elementData[--size] = null;
return elementData[index];
}
/**
* 修改index 对应元素的值
*
* @param index
* @param element
* @return
*/
public Object set(int index, Object element) {
if (index >= size || index < 0) {
throw new RuntimeException("index is wrong");
}
elementData[index] = element;
return element;
}
public static void main(String[] args) {
ArrayListDemo list = new ArrayListDemo(1);
list.add("11111");
list.add("22222");
list.set(0, "0000");
System.out.println(list.get(0));
}
}
LinkedList
package com.demo.utils.Test_Collection;
/**
* @author zhaod
* @description LinkedList 主要是采用链表实现的
* @date 2018/5/9 15:32
*/
/**
* 节点类
*/
class Node {
// 前一个节点
public Node previous;
// 改节点存储的数据
public Object object;
// 下一个节点
public Node next;
public Node() {
}
public Node(Node previos, Object object, Node next) {
super();
this.previous = previos;
this.object = object;
this.next = next;
}
}
public class LinkedListDemo {
private Node first;
private Node last;
private int size;
public int size() {
return size;
}
/**
* 添加元素
* @param object
*/
public void add(Object object) {
if (first == null) {
Node n = new Node();
n.previous = null;
n.object = object;
n.next = null;
first = n;
last = n;
} else {
Node n = new Node();
n.previous = last;
n.object = object;
n.next = null;
last.next = n;
last = n;
}
size++;
}
/**
* 获取元素
* @param index
* @return
*/
public Object get(int index) {
// 带查找的节点
Node temp = null;
if (first == null) {
return null;
} else {
temp = first;
for (int i = 0; i < index; i++) {
temp = temp.next;
}
return temp.object;
}
}
/**
* 删除元素
* @param index
* @return
*/
public Object remove(int index) {
// 待删除的节点
Node temp = null;
if (first != null) {
temp = first;
for (int i = 0; i < index; i++) {
temp = temp.next;
}
}
if (temp != null) {
// 删除节点的上一个节点
Node up = temp.previous;
// 待删除节点的下一个节点
Node down = temp.next;
up.next = down;
down.previous = up;
temp = null;
size--;
}
return null;
}
public static void main(String[] args) {
LinkedListDemo linkedLis = new LinkedListDemo();
linkedLis.add("one");
linkedLis.add("two");
linkedLis.add("three");
linkedLis.remove(0);
for (int i = 0; i < linkedLis.size(); i++) {
System.out.println(linkedLis.get(i));
}//
}
}
4 Map接口
HashMap,HashTable
- HashMap效率高,线程不安全,HashTable线程安全,效率低
- 实现Map接口的类用来存储键key值value对
- Map接口的实现类有HashMap和TreeMap
- Map类中存储使用键标识,所以键不可以重复哦
package com.zhao.collection;
import java.util.HashMap;
import java.util.Map;
/**
* Map
* @author zhao_di
*
*/
public class Demo02 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Map map = new HashMap();
// 放置元素
map.put("1", "zhaodi");
// 如果键重复 那么会覆盖之前的值
map.put("1", "zhaodi2");
// 根据键获取元素
String str = (String)map.get("1");
map.size();
// 移除
// map.remove("1");
// 是否包含键
System.out.println(map.containsKey("1"));
// 是否包含值
System.out.println(map.containsValue("zhaodi2"));
// 清楚容器
map.clear();
System.out.println(map.get("1"));
}
}
自己实现HashMap,HashTable
HashMap
- 采用数组实现
package com.demo.utils.Test_Collection;
/**
* @author zhaod
* @description 自定义实现Map功能1.0
* 采用数组实现的效率很低,下个版本采用hash表实现
* @date 2018/5/10 9:17
*/
public class HashMapDemo {
Entry[] entries = new Entry[1000];
int size;
/**
* 存键值对key-value
*
* @param key
* @param value
*/
public void put(Object key, Object value) {
Entry entry = new Entry(key, value);
// 重复的键覆盖值
for (int i = 0; i < size; i++) {
if (entries[i].key.equals(key)) {
entries[i].value = value;
}
}
entries[size++] = entry;
}
/**
* 根据key获取value
*
* @param key
* @return
*/
public Object get(Object key) {
for (int i = 0; i < size; i++) {
if (entries[i].key.equals(key)) {
return entries[i].value;
}
}
return null;
}
/**
* map是否包含指定的key
*
* @param key
* @return
*/
public boolean containKey(Object key) {
for (int i = 0; i < size; i++) {
if (entries[i].key.equals(key)) {
return true;
}
}
return false;
}
public static void main(String[] args) {
HashMapDemo map = new HashMapDemo();
map.put("1", "one");
map.put("2", "two");
System.out.println(map.get("2"));
}
}
class Entry {
public Object key;
public Object value;
public Entry(Object key, Object value) {
this.key = key;
this.value = value;
}
}
- 采用数组+链表(hash表实现)
package com.demo.utils.Test_Collection;
import java.util.LinkedList;
/**
* @author zhaod
* @description 采用hash表实现hashMap,
* 效率高
* @date 2018/5/10 15:42
*/
public class HashMapDemo2 {
LinkedList[] array = new LinkedList[1000];
int size;
/**
* 存值
* @param key
* @param value
*/
public void put(Object key, Object value) {
int a = key.hashCode() % 1000;
Entry entry = new Entry(key, value);
if (array[a] == null) {
LinkedList list = new LinkedList();
list.add(entry);
array[a] = list;
} else {
LinkedList list = array[a];
for(int i=0;i<list.size();i++){
Entry e = (Entry) list.get(i);
if(entry.key.equals(key)){
e.value = value;
return;
}
}
array[a].add(entry);
}
}
public Object get(Object key) {
//return entries[key.hashCode()%1000].value;
int a = key.hashCode()%1000;
if(array[a]!=null){
LinkedList list = array[a];
for(int i=0;i<list.size();i++){
Entry entry = (Entry) list.get(i);
if(entry.key.equals(key)){
return entry.value;
}
}
}
return null;
}
public static void main(String[] args) {
HashMapDemo2 map = new HashMapDemo2();
map.put(1, 1);
map.put(2, 2);
map.put(2, 3);
System.out.println(map.get(1));
System.out.println(map.get(2));
}
}
5 Set
- Set接口是Collection接口的子接口,Set接口没有提供额外的方法
- Set接口的特性是容器类中的元素是没有顺序的,而且不可以重复哦
- 常用的实现类有HashSet,TreeSet,底层是HashMap实现的
HashSet
public static void main(String[] args) {
Set set = new HashSet();
set.add("22");
set.add("22");// 重复
String string = new String("22");
String string2 = new String("22");
set.add(string);// 重复
set.remove("22");
System.out.println(string==(string2));
System.out.println(set.size());//2
}
自己实现HashSet
package com.demo.utils.Test_Collection;
import java.util.HashMap;
/**
* @author zhaod
* @description 1、Set是collection接口的子接口,和list的同一级别
* <p>
* 2、Set的特点就是无序,不可重复
* <p>
* 3、常用的实现类有HashSet,treeSet
* 4、底层就是采用map实现的,set的值存在map的key位置上,value处赋值static final Object
* @date 2018/5/11 10:39
*/
public class HashSetDemo {
private HashMap map;
/**
* map中的value
*/
private static final Object PRESENT = new Object();
/**
* 构造方法
*/
public HashSetDemo() {
map = new HashMap();
}
/**
* 添加元素,set的值存放在map的key上面
* @param object
*/
public void add(Object object) {
map.put(object, PRESENT);
}
/**
* 获取set的大小
* @return
*/
public int size(){
return map.size();
}
public static void main(String[] args) {
//Set<String> set = new HashSet<String>();
HashSetDemo set = new HashSetDemo();
set.add("zhaodi");
set.add("tom");
set.add("rose");
set.add("jack");
}
}
6 遍历容器
- 所有实现了collection接口的容器类都有一个iterator方法用以返回一个实现了Iterator接口的对象
- Iteration对象叫做迭代器,用以方便的对实现对容器内元素的便利操作
遍历List
1、通过索引
- 可以删除集合中的元素
ArrayList<String> arrayList = new ArrayList<String>();
arrayList.add("1");
arrayList.add("2");
arrayList.add("3");
arrayList.add("4");
// for循环
for(int i=0;i<arrayList.size();i++){
arrayList.remove(i);
//arrayList.removeAll(arrayList);
System.out.println(arrayList.get(i));
}
2、通过增强for循环
- 底层还是迭代器实现的,不提供方法删除集合中的元素
for(String str: arrayList){
System.out.println(str);
}
3、通过迭代器
- 迭代器相当于给集合上了锁,在此期间只可以通过迭代器的remove()删除元素
- 不可以通过集合提供的remove删除元素
Iterator<String> iterator = arrayList.iterator();
while(iterator.hasNext()){// 判断是否有元素没有被遍历
String string = iterator.next();
//System.out.println(iterator.next());// 返回游标当前位置的元素并将游标移动到下一个位置
/*if(string.equals("2")){
iterator.remove();
}*/
iterator.remove();// 删除游标左边的元素,在执行完next之后该操作只可以执行一次
}
4、lambda遍历
。。。。
List<String> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add("hello_" + i);
}
list.forEach(s -> {
System.out.println(s);
});
。。。。
遍历Map
1、增强for循环遍历
- 这种方式不可以删除map里面的数据
Map<Integer,String> map = new HashMap<Integer,String>();
map.put(1, "1");
map.put(2, "2");
map.put(3, "3");
map.put(4, "4");
// 方式一 :这是最常见的并且在大多数情况下也是最可取的遍历方式。在键值都需要时使用。
for(Map.Entry<Integer, String> entry : map.entrySet()){
System.out.println(entry.getKey() + entry.getValue());
}
// 方法二: 如果只需要map中的键或者值,你可以通过keySet或values来实现遍历,而不是用entrySet。
// 性能稍微好点 快10%
for(Integer key : map.keySet()){
System.out.println("key:"+key);
}
for(String val: map.values()){
System.out.println("value:"+val);
}
2、迭代器遍历
- 可以进行删除元素
Iterator<Map.Entry<Integer, String>> entries = map.entrySet().iterator();
while(entries.hasNext()){
Map.Entry<Integer, String> entry = entries.next();
System.out.println("3key:"+entry.getKey()+";3value:"+entry.getValue());
if(entry.getKey() == 1){
entries.remove();
}
}
Iterator<Map.Entry<Integer, String>> entries1 = map.entrySet().iterator();
while(entries1.hasNext()){
//如果这里的entries1不换个名字,那么接着上面的hasNext,会出现指针在最后一个位置
Map.Entry<Integer, String> entry = entries1.next();
System.out.println("4key:"+entry.getKey()+";3value:"+entry.getValue());
}
- 总结
- 迭代器遍历可提供了方法删除元素
- 增强for循环的底层就是迭代器,不可以采用集合本身的remove删除元素