一.List接口
1.特点
- 有序
- 有索引
- 可重复,元素可为null
- 底层用数组实现
2. ArrayList
2.1 实现
public class MyArrayList {
/**
* 定义数组,保存数据
*/
private Object[] objects = null;
/**
* 默认数组长度
*/
private final int DEFAULT_LENGTH = 10;
/**
* 数组长度
*/
private int length;
/**
* 数组元素个数
*/
private int size= 0;
/**
* 默认构造函数,创建数组
*/
private final int LOAD = 2;
public MyArray() {
length = DEFAULT_LENGTH;
objects = new Object[length];
}
/**
* 构造函数,根据用户传入长度创建数组
* @param length
*/
public MyArray(int length) {
this.length = length;
objects = new Object[length];
}
/**
* 向数组中添加元素
* @param o
*/
public void add(Object o) {
//判断是否需要扩容
if(size==length) {
//元素个数等于了数组长度,需要扩容
length = length*LOAD;
objects = Arrays.copyOf(objects,length);
}
objects[size]=o;
size++;
}
public void add(int index,Object o) {
if(index<0||index>size-1) {
throw new ArrayIndexOutOfBoundsException("访问越界");
}else {
//判断是否需要扩容
if(size==length) {
//元素个数等于了数组长度,需要扩容
length = length*LOAD;
objects = Arrays.copyOf(objects,length );
}
//先将index位置处的元素已近后面元素向右移动
System.arraycopy(objects, index, objects, index+1, size-index);
objects[index] = o;
size++;
}
}
/**
* 数组移除操作
* @param index
*/
public void remove(int index) {
if(index<0||index>size-1) {
throw new ArrayIndexOutOfBoundsException("访问越界");
}else {
objects[index]= null;
System.arraycopy(objects, index+1, objects,index , size-index);
size--;
}
}
/**
* 查找元素所在的位置
* @param o
* @return
*/
public int indexOf(Object o) {
// if(size==0) {
// return size;
// }else if(size==length) {
// return -1;
// }else if(size=0?true:false;
}
/**
* 移除所有元素
*/
public void removeAll() {
Arrays.fill(objects, null);
size =0;
}
/**
* 更新数组元素
* @param index
* @param o
*/
public void update(int index,Object o) {
if(index<0||index>size-1) {
throw new ArrayIndexOutOfBoundsException("访问越界");
}
objects[index] = o;
}
/**
* 查找某个索引处的元素
* @param index
*/
public Object get(int index) {
if(index<0||index>size-1) {
throw new ArrayIndexOutOfBoundsException("访问越界");
}
return objects[index];
}
/**
* 打印数组元素
*/
@Override
public String toString() {
StringBuffer sb = new StringBuffer("[");
for (int i = 0; i < size; i++) {
sb.append(objects[i]);
sb.append(",");
}
sb.append("]");
return sb.toString().replace(",]", "]");
}
/**
* 获取元素个数
* @return
*/
public int size() {
return size;
}
}
2.2 方法
方法 |
描述 |
add(Object o) |
添加数据 |
add(int index,Object o) |
在制定索引处添加元素 |
size() |
获取元素个数 |
get(int index) |
获取索引处的元素 |
isEmpty() |
判断集合是否为空 |
indexOf(Object o) |
判断某个元素第一次出现的位置 |
E remove(int index) |
移除索引处元素,并返回该元素 |
boolean remove(Object o) |
移除元素 |
clear() |
清空元素 |
set(int index ,E e) |
修改索引处的元素 |
iterator() |
获取迭代器 |
trimToSize() |
减少容量指当前元素个数 |
contains(Object o) |
判断是否包含某个元素 |
lastIndexOf(Object o) |
判断某个元素最后一次出现的位置 |
toArray() |
将集合转换为数组 |
addAll(Collection extends E> c) |
集合中添加集合 |
addAll(int index, Collection extends E> c) |
索引处添加集合 |
retainAll(Collection c) |
求两个集合的交集 |
removeAll(Collection> c) |
移除传入集合内的元素 |
subList(int fromIndex, int toIndex) |
获取子集合 |
2.3List遍历
public static void main(String[] args) {
//菱形语法
ArrayList list = new ArrayList<>();
list.add(1);
list.add(4);
list.add(2);
for (Integer integer : list) {
System.out.println(integer);
}
//使用迭代器遍历
Iterator it = list.iterator();
//判断是否有下一个元素
while (it.hasNext()) {
int i = it.next();
System.out.println(i);
}
}
3.LinkedList
3.1双向链表实现
public class MyLinkedList{
/**
* 链表元素个数
*/
private int size;
/**
* 链表首节点
*/
private Node first;
/**
* 链表尾结点
*/
private Node last;
/**
* 默认构造创建一个空链表
*/
public MyLinkedList() {
first = null;
last = null;
size = 0;
}
/**
* 在链表末尾添加元素
* @param e
*/
private void linkLast(E e) {
if(first==null||last==null||size==0) {
//说明链表为空链表
//1.创建新节点
//2.新节点指为first
//3.新节点指为last
Node newNode = new Node(null,e,null);
first = newNode;
last = newNode;
}else {
//1.创建新节点
Node newNode = new Node(last,e,null);
//2.将last节点指向新节点
last.next = newNode;
//3.将新节点改为last
last = newNode;
}
size++;
}
/**
* 在链表首部添加节点
* @param e
*/
private void linkFirst(E e) {
if(first==null) {
//1.创建新节点
Node newNode = new Node(null, e, null);
first = newNode;
last = newNode;
}else {
Node newNode = new Node(null, e, first);
first.pre = newNode;
first = newNode;
}
size++;
}
/**
* 在节点之前添加节点
* @param index
* @param e
*/
private void linkBefore(int index,E e) {
chcekRange(index);
//1.创建新节点
Node node = new Node(null,e,null);
//2.找到索引处的节点
Node indexNode = getNodeByIndex(index);
//3.找到索引处的前置节点
Node pre = indexNode.pre;
//4.新节点指向前置节点
node.pre = pre;
//5.前置节点指向新节点
pre.next = node;
//6.新节点指向索引处节点
node.next = indexNode;
//7.索引处pre指向新节点
indexNode.pre=node;
size++;
}
/**
* 在某个节点后插入新节点
* @param index
* @param e
*/
private void linkAfter(int index,E e) {
chcekRange(index);
//1.获取当前索引处的节点
Node indexNode = getNodeByIndex(index);
//2.获取索引处后置节点
Node next = indexNode.next;
//3.创建新节点
Node newNode = new Node(indexNode,e,next);
//4.索引处节点指向新节点
indexNode.next = newNode;
//5.索引处节点的后置节点指向新节点
next.pre = newNode;
size++;
}
/**
* 链表中添加节点,默认添加在尾部
* @param e
*/
public void add(E e) {
linkLast(e);
}
/**
* 在指定索引处后面添加节点
* @param index
* @param e
*/
public void add(int index,E e) {
linkAfter(index, e);
}
/**
* 删除索引处节点
* @param index
* @return
*/
public boolean remove(int index) {
chcekRange(index);
if(index==0) {
Node removeNode = first;
first = first.next;
first.pre = null;
removeNode.next=null;
}else if(index==size-1) {
Node removeNode = last;
last = last.pre;
last.next = null;
removeNode.pre = null;
}else {
//1.找到索引处的节点
Node indexNode = getNodeByIndex(index);
//2.找到索引处的后置
Node next = indexNode.next;
//3.找到索引处的前置节点
Node pre = indexNode.pre;
//4.将索引处前置节点的next指向索引处后置节点
pre.next = next;
//5.将索引处后置节点的pre指向索引处前置节点
next.pre = pre;
//6.减少元素个数
}
size--;
return true;
}
/**
* 根据索引获取元素
* @param index
* @return
*/
public E get(int index) {
chcekRange(index);
Node node = getNodeByIndex(index);
return node.data;
}
/**
* 修改索引处的值
* @param index
* @param e
*/
public void set(int index,E e) {
chcekRange(index);
Node current = first;
for (int i = 0; i < size&¤t!=null;i++,current = current.next) {
if(i==index) {
current.data = e;
}
}
}
/**
* 清空链表
*/
public void clear() {
first =null;
last =null;
size=0;
}
/**
* 链表是否为空
* @return
*/
public boolean isEmpty() {
return size==0;
}
/**
* 根据传入的索引找到节点
* @param i
* @return
*/
private Node getNodeByIndex(int index){
//判断索引越界
if(index<0||index>size) {
throw new IndexOutOfBoundsException("访问越界");
}
if(index==0) {
return first;
}else if(index==size-1) {
return last;
}else {
Node current = first;
for (int i = 0; i < size&¤t!=null; i++) {
if(i==index) {
return current;
}
current = current.next;
}
}
return first;
}
/**
* 判断访问是否越界
* @param index
*/
public void chcekRange(int index) {
if(index<0||index>size-1) {
throw new IndexOutOfBoundsException("访问越界");
}
}
/**
* 打印链接
*/
@Override
public String toString() {
if(size==0) {
return "[]";
}
Node current = first;
StringBuffer sb =new StringBuffer("[");
for (int i = 0; i < size&¤t!=null; i++,current=current.next) {
sb.append(current.data);
if(i!=size-1) {
sb.append(",");
}
}
sb.append("]");
return sb.toString();
}
/**
* 定义非静态内部类表示节点
* @author MR.W
*
* @param
*/
class Node{
Node pre;
E data;
Node next;
public Node(Node pre, E data, Node next) {
super();
this.pre = pre;
this.data = data;
this.next = next;
}
}
}
3.2 方法
方法 |
描述 |
add(Object o) |
添加数据 |
add(int index,Object o) |
在指定索引处添加元素 |
size() |
获取元素个数 |
get(int index) |
获取索引处的元素 |
isEmpty() |
判断集合是否为空 |
indexOf(Object o) |
判断某个元素第一次出现的位置 |
E remove(int index) |
移除索引处元素,并返回该元素 |
boolean remove(Object o) |
移除元素 |
clear() |
清空元素 |
set(int index ,E e) |
修改索引处的元素 |
addFirst(E e) |
链表首部添加元素 |
addLast(E e) |
链表末尾添加元素 |
removeFirst() |
移除首节点 |
removeLast() |
移除尾节点 |
getFirst() |
获取第一个节点 |
getLast() |
获取最后一个几点 |
二.Set接口
1.特点
- 无序
- 无索引
- 不可重复
2.HashSet
2.1方法
方法 |
描述 |
add(Object o) |
添加元素 |
remove(Object o) |
移除元素 |
isEmpty() |
判断元素是否为空 |
2.2.HashSet遍历
public class Test {
public static void main(String[] args) {
Set set = new HashSet<>();
//添加元素
set.add("陈忠实");
set.add("贾平凹");
set.add("路遥");
set.add("张爱玲");
set.add("林徽因");
boolean a = set.add("徐志摩");
System.out.println(a);
boolean b = set.add("徐志摩");
System.out.println(b);
//foreach
for (String s : set) {
System.out.println(s);
}
//iterator
Iterator it = set.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
}
}
2.3重写hashCode规则
- 同一对象多次调用hashCode()方法时,返回值应该相同
- equals()方法返回值为true时,hashCode应该相同
- 所有参与equals方法的成员变量,都应该参与hashCode计算(为防止偶然和相等,造成hash冲突,应该用每个成员变量乘以一个质数)
3.TreeSet
三.Map接口
1.HashMap
1.1方法
方法 |
描述 |
put(K key,V value) |
添加键值对 |
get(Object key) |
根据键获取值 |
keySet() |
获取keySet |
entrySet() |
获取entrySet |
containsKey(Object key) |
判断是否存在key |
remove(Object key) |
根据key删除键值对 |
remover(Object key,Object value) |
根据key和value删除键值对 |
size() |
获取元素个数 |
isEmpty() |
判断map是否为空 |
1.2HashMap遍历
//利用keySet()方法获取keySet
public static void main(String[] args) {
Map map = new HashMap();
map.put("乔峰",30);
map.put("虚竹", 20);
map.put("李秋水", 20);
map.put("天山童姥", 60);
map.put("梦姑",18);
//先获取keySet
Set set = map.keySet();
//获取迭代器
Iterator it = set.iterator();
//利用迭代器遍历
while (it.hasNext()) {
String key = it.next();
int i = map.get(key);
System.out.println("key==========="+key);
System.out.println("value========="+i);
}
}
//利用entrySet()获取entrySet
public static void main(String[] args) {
Map map = new HashMap();
map.put("乔峰",30);
map.put("虚竹", 20);
map.put("李秋水", 20);
map.put("天山童姥", 60);
map.put("梦姑",18);
//获取键值对集合
Set> set = map.entrySet();
//遍历set
for (Entry entry : set) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println("key=========="+key);
System.out.pintln("key=========="+value);
}
}
1.3HashMap和Hashtable的 区别
HashMap和Hashtable都是Map接口的子类
HashMap的key和value都可以为null,只能存入一个为null的key,Hashtable的key和value都不能为null
HashMap非线程安全,Hashtable线程安全
2.TreeMap
四.面试题
- ArrayList,Vector,LinkedList的区别
- ArrayList,Vector底层实现是数组,LinkedList底层实现是双向链表
- Vector线程安全,ArrayList,LinkedList非线程安全
- ArrayList,Vector查找快,增删慢,LinkedList增删快,查找慢
- ArrayList,Vector,LinkedList都是List接口的实现类
- ArrayList,Vector,LinkedList都有序,有索引,可重复。