Day19 集合、List、链表、比较器
1. 集合
1.1 概述
1.2 继承体系
由以上两图我们可以看出Java集合类有清晰的继承关系,有很多子接口和实现类。但是,并不是所有子接口或实现类都是最常用的。
下面我们列举出最常用的几个子接口和实现类:
Collection ——> List ——> ArrayList类
Collection ——> List ——> LinkedList类
Collection ——> Set ——> HashSet类
Collection ——> Set ——> SortedSet接口 ——> TreeSet类
Map ——> HashMap类
Map ——> SortedMap ——> TreeMap类
2. Collection
2.1 方法
2.2 使用
public static void main(String[] args) {
//创建 集合
Collection c1 = new ArrayList();
System.out.println(c1.isEmpty());
//基本类型先进行自动装箱,然后再向上转型
c1.add(1);
System.out.println(c1.isEmpty());
System.out.println(c1.size());
c1.add("xxx");
System.out.println(c1.size());
//转换为数组进行遍历
Object[] objects = c1.toArray();
for (Object object : objects) {
System.out.println(object);
}
//删除
c1.remove("xxx");
System.out.println(c1.size());
//清空集合
c1.clear();
System.out.println(c1.isEmpty());
}
2.3 注意
* boolean contains(Object o):判断是否包含某个元素
*
* boolean remove(Object o):删除指定元素
*
* 这两个方法,底层都会调用equals方法进行比较
*
* 比如 c.contains("abc");会用abc调用equals方法和集合中所有的元素进行比较
*
* 所以 如果我们要存储的是自定义的类型,比如User等,那么想要使用contains和remove 就需要覆写equals方法
public static void main(String[] args) {
Collection c = new ArrayList();
c.add(1);
c.add(new Integer(1));
System.out.println(c.size());
Integer i1 = new Integer(1);
//Integer的equals方法覆写了,比较的是值
//contains会调用equals方法
System.out.println(c.contains(i1));
Manager m1 = new Manager(1, "张三");
Manager m2 = new Manager(1, "张三");
c.add(m1);
System.out.println(c.contains(m2));
}
}
class Manager {
private int no;
private String name;
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof Manager) {
Manager manager = (Manager) obj;
if (no == manager.no && name.equals(manager.name)) {
return true;
}
}
return false;
}
public Manager(int no, String name) {
super();
this.no = no;
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
3. Iterator
3.1 概述
3.2 方法
3.3 使用
public static void main(String[] args) {
Collection collection = new ArrayList();
collection.add("asd");
collection.add("123");
collection.add("avc");
collection.add("xxx");
collection.add(false);
//生成迭代器
Iterator it = collection.iterator();
//迭代器一旦创建,就不能对集合更改,否则就需要重新生成迭代器
// collection.add(1);
//collection.remore("asd")
collection.add(1);
it = collection.iterator();
//遍历
while (it.hasNext()) {
Object object = it.next();
System.out.println(object);
//如果再使用迭代器的过程中,需要进行删除,必须使用迭代器的remove方法
//不能使用集合的删除
//it.remove()
}
it = collection.iterator();
while (it.hasNext()) {
Object object = it.next();
System.out.println(object);
}
}
4. List
4.1 概述
* List :有序可重复
* 存入顺序和去除顺序是一致得
*
* ArrayList:底层是数组,查询和更改效率极高,添加和删除效率较低
*
* LinkedList:底层是双向链表,查询效率较低,添加删除效率较高
*
* Vector:已经过时,底层也是数组,ArrayList是Vector的升级版
* Vector默认容量是10,扩大容量是二倍,线程安全,效率较低
* ArrayList默认容量是10,扩大容量是1.5倍,非线程安全,效率较高
4.2 ArrayList
public static void main(String[] args) {
//底层是Object[]数组,也就意味着只能保存引用类型
//但是由于基本类型会自动装箱为包装类类型,所以导致Object[] 数组什么都能放
List list = new ArrayList();
//add(E e):将元素添加到泪飙的尾部
list.add(11);
//add(int index,E e):将元素添加到列表的指定位置
list.add(0, 22);
//ArrayList覆写了toString方法,所以打印结果不是内存地址 二十里面的数据[22,11]
System.out.println(list);
// set(int index, E element):替换指定位置上的元素
list.set(1, 33);
System.out.println(list);
//get(int index):根据索引获取对应的元素
System.out.println(list.get(1));
//remove(int index):根据索引删除元素
list.remove(1);
//remove(Object obj):根据指定元素
//应该手动吧22封装到Integer类型中
list.remove(new Integer(22));
System.out.println(list);
list.add(1);
list.add(2);
list.add(3);
list.add(4);
//迭代器
Iterator it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
//forEach
for (Object object : list) {
System.out.println(object);
}
//for
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
4.3 LinkedList
4.3.1 概述
* LinkedList:底层是双向链表
* 链表的节点 有三个部分构成:1添加的元素,2下一个节点的引用了,3上一个节点的引用
* 链表数据结构,在内存中储存也不是连续的,所以没有固定的下标,因此查询效率低
* 因为内存空间不是连续的,只是能找到下一个节点,因此添加和删除就变得容易了
4.3.2 基本使用
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
//尾部添加 成功返回true
linkedList.add(1);
//头部添加
linkedList.push(2);
//尾部
linkedList.addLast(3);
//首部 成功返回true
linkedList.addFirst(4);
//首部
linkedList.offerFirst(5);
//尾部
linkedList.offerLast(6);
System.out.println(linkedList);
//本质调用 都是linkLast 和linkFirst,所以他们没有区别,主要解决命名习惯问题
System.out.println(linkedList.getLast());
System.out.println(linkedList.getFirst());
//根据下标获取,只不过这个下标决定的是虚幻的次数,模拟出来下标获取数据而已
//和数组的下标是两回事,因为链表是没有下标的
System.out.println(linkedList.get(3));
//改,设置对应下标的数据
linkedList.set(1, 2);
//根据索引删除
linkedList.remove(1);
//根据对象删除
linkedList.remove(new Integer(2));
//获取首元素,并把它删除
linkedList.poll();
//获取最后一个并删除
linkedList.pop();
}
4.3.3 底层实现
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++;
}
add,push,offerFirst,addFirst调用的底层方法linkLast(首部添加)
E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
LinkedList的remove方法调用的底层方法