集合框架图
List接口三个实现类
- ArrayList:底层由数组实现,线程不安全,效率高;所以随机访问快,修改、插入、删除慢
- LinkedList:底层由链表实现,线程不安全,效率高;所以查询慢,修改,插入,删除快
- Vector:线程安全,效率低
自己实现ArrayList类
/**
* 自己实现一个简单的ArrayList,帮助我们更好的理解ArrayList类的底层结构
* @author L J
*
*/
public class LArrayList {
//存储元素[核心数组]
private Object[] elementData;
//代表容器大小
private int size;
//获取容器大小
public int size() {
return size;
}
//容器是否为空
public boolean isEmpty() {
return size == 0;
}
public LArrayList() {
this(10);
}
public LArrayList(int initialCapacity) {
if(initialCapacity < 0) {
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
elementData = new Object[initialCapacity];
}
//范围检查
private void rangeCheck(int index) {
if(index < 0 || index >= size) {
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//扩容
private void ensureCapacity() {
//数组扩容
if(size >= elementData.length) {
Object[] newArray = new Object[(size + 1) * 2];
//数组拷贝
//System.arraycopy(elementData, 0, newArray, 0, elementData.length);
for(int i = 0; i < elementData.length; i++) {
newArray[i] = elementData[i];
}
elementData = newArray;
}
}
//添加元素
public void add(Object obj) {
ensureCapacity();
elementData[size++] = obj;
//size++;
}
public void add(int index, Object obj) {
rangeCheck(index);
ensureCapacity();
System.arraycopy(elementData, index, elementData, index + 1, size - index);
elementData[index] = obj;
size++;
}
//获取元素
public Object get(int index) {
rangeCheck(index);
return elementData[index];
}
//从容器中移除指定位置的元素
public void remove(int index) {
rangeCheck(index);
//需要向前移动的元素的个数
int numMoved = size - index - 1;
if(numMoved > 0) {
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
}
//最后一个元素变为空
elementData[--size] = null;
}
//删除一个指定元素
public void remove(Object obj) {
for(int i = 0; i < size; i++) {
if(get(i).equals(obj)) { //底层调用equals方法,而非==
remove(i);
}
}
}
//在指定的索引位置更新一个元素
public Object set(int index, Object obj) {
rangeCheck(index);
Object oldValue = elementData[index];
elementData[index] = obj;
return oldValue;
}
}
自己实现LinkedList类
/**
* 自己实现一个LinkedList类
* @author L J
*/
public class LLinkedList {
//头节点
private Node first;
//尾节点
private Node last;
//表示容器的大小
private int size;
//获取容器大小
public int size() {
return size;
}
//添加一个元素
public void add(Object obj) {
Node n = null;
if(first == null) {
n = new Node();
n.setPrevious(null); //头节点始终是null
n.setObj(obj);
n.setNext(null); //还没有下一个节点
//创建的第一个节点,即是头节点,也是尾节点
first = n;
last = n;
}else{
//直接往last节点后增加新的节点
n = new Node();
n.setPrevious(last);
n.setObj(obj);
n.setNext(null);
//当前节点指向新创建的节点
last.setNext(n);
//当前最后一个节点是新创建的节点
last = n;
}
size++;
}
//范围检查
private void rangeCheck(int index) {
if(index < 0 || index >= size) {
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//获取对应索引位置的一个元素
public Object get(int index) {
rangeCheck(index);
Node temp = node(index);
if(temp != null) {
return temp.obj;
}
return null;
}
//遍历找到对应位置的节点
public Node node(int index) {
Node temp = null;
if(first != null) {
//分别从前后遍历链表,提高效率
if(index < (size >> 1)) {
temp = first;
for(int i = 0; i < index; i++) {
temp = temp.next;
}
}else{
temp = last;
for(int i = size - 1; i > index; i--) {
temp = temp.previous;
}
}
}
return temp;
}
//移除一个元素
public void remove(int index) {
rangeCheck(index);
Node temp = node(index);
if (temp != null) {
Node up = temp.previous;
Node down = temp.next;
//移除首尾元素时会抛出空指针异常,看源码解决
up.next = down;
down.previous = up;
size--;
}
}
//在指定位置插入一个元素
public void add(int index, Object obj) {
rangeCheck(index);
//创建新节点
Node newNode = new Node();
newNode.obj = obj;
Node temp = node(index);
if(temp != null) {
Node up = temp.previous;
//对头节点操作的时候也会抛出空指针异常
up.next = newNode;
newNode.previous = up;
newNode.next = temp;
temp.previous = newNode;
size++;
}
}
}
自定义Map
/**
* 自己实现一个Map类,效率较低
* @author L J
*/
public class LMap {
//此类重在理解Map,所以数组扩容等忽略
LEntry[] arr = new LEntry[999];
//表示容器大小
int size;
//获取容器大小
public int size() {
return size;
}
//向Map中添加一个元素
public void put(Object key, Object value) {
LEntry e = new LEntry(key, value);
//键不能重复[键相同,就用新值覆盖旧值]
for(int i = 0; i < size; i++) {
if(arr[i].key.equals(key)) {
arr[i].value = value;
return;
}
}
arr[size++] = e;
}
//通过key获取一个元素
public Object get(Object key) {
for(int i = 0; i < size; i++) {
if(arr[i].key.equals(key)) {
return arr[i].value;
}
}
return null;
}
//检测是否包含key
public boolean containsKey(Object key) {
for(int i = 0; i < size; i++) {
if(arr[i].key.equals(key)) {
return true;
}
}
return false;
}
//检测是否包含value
public boolean containsValue(Object value) {
for(int i = 0; i < size; i++) {
if(arr[i].value.equals(value)) {
return true;
}
}
return false;
}
}
//entry是条目的意思[键值对]
class LEntry {
Object key;
Object value;
public LEntry(Object key, Object value) {
super();
this.key = key;
this.value = value;
}
}
升级版Map
/**
* 自定义Map升级版
* @author L J
*/
public class LMap01 {
//map的底层结构,数组+链表,数组中存储链表
LinkedList[] arr = new LinkedList[999];
//容器大小
int size;
//获取容器大小
public int size() {
return size;
}
//向Map中添加一个元素
public void put(Object key, Object value) {
LEntry e = new LEntry(key, value);
int hash = key.hashCode();
hash = hash < 0 ? -hash : hash;
int a = hash % arr.length;
if(arr[a] == null) {
//创建一个链表
LinkedList list = new LinkedList();
arr[a] = list;
//将键值对存入链表
list.add(e);
}else{
//取得链表
LinkedList list = arr[a];
//key相同,覆盖value
for(int i = 0; i < list.size(); i++) {
LEntry e1 = (LEntry) list.get(i);
if(e1.key.equals(key)) {
e1.value = value;
}
}
arr[a].add(e);
}
size++;
}
//通过key获取一个元素
public Object get(Object key) {
int hash = key.hashCode();
hash = hash < 0 ? -hash : hash;
int a = hash % arr.length;
if(arr[a] != null) {
//取得链表
LinkedList list = arr[a];
//遍历找出key对应的value
for(int i = 0; i < list.size(); i++) {
LEntry e = (LEntry) list.get(i);
if(e.key.equals(key)) {
return e.value;
}
}
}
return null;
}
}
equals和hashCode
java中规定,两个内容相同的对象,应该具有相同的hashCode;重写equals方法必须重写hashCode方法
//重写equals和hashCode方法
public class Student {
private int id;
private String name;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
//散列
result = prime * result + id;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (id != other.id)
return false;
return true;
}
}
自定义HashSet类
/**
* 自定义HashSet类
* @author L J
*/
public class LHashSet {
//Set的底层实现是Map
HashMap map;
private static final Object PRESENT = new Object();
//表示容器的大小
int size;
//构造器
public LHashSet() {
map = new HashMap();
}
//获取容器的大小
public int size() {
return map.size();
}
//向Set中添加元素
public void add(Object o) {
//Set不可重复就是利用了Map中键不可重复这一特点
map.put(o, PRESENT);
}
}
遍历Map的两种方式
@Test
public void testMap1() {
Map<Integer,String> map = new HashMap<Integer, String>();
map.put(100, "jack"); //key = 100 value = "jack"
map.put(200, "marry");
map.put(300, "sisi");
Set<Integer> set = map.keySet();//只获取key值,将map转换为set
Iterator<Integer> it = set.iterator();
while(it.hasNext()) {
Integer key = it.next();
String value = map.get(key);
System.out.println(key + "-" + value);
}
}
@Test
public void testMap2() {
Map<Integer,String> map = new HashMap<Integer, String>();
map.put(100, "jack");
map.put(200, "marry");
map.put(300, "sisi");
Set<Entry<Integer, String>> set = map.entrySet();//entry中存储的是记录<key,value>
Iterator<Entry<Integer, String>> it= set.iterator();
while(it.hasNext()) {
Entry<Integer, String> entry = it.next();
Integer key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "<->" + value);
}
}
}