集合
概述
?继承体系
?
?由以上两图,我们可以看出java集合类有清晰的继承关系,有很多子接口和实现类。但是并不是所有子接口或实现类都是最常用的。
下面我们列举出最常用的几个子接口和实现类;
Collection———>List----->Arraylist类
Collection------>List----->LinkedList类
Collection--->Set---->HashSet类
Collection----Set---SortedSet接口-->TreeSet类
Map——>HashMap类
Map————>SortedMap————>TreeMap类
Collection
方法
?使用
package day7_15;
import java.util.ArrayList;
import java.util.Collection;
/**
* collection 是集合的父类,所以collection中的方法是集合中每个子类都有的
* @author 啊超
* @Date 2021年7月15日
*/
public class Collection_1 {
public static void main(String[] args){
//创建集合
Collection c1=new ArrayList();
System.out.println(c1.isEmpty()); //isEmpty 为空,//true
//基本数据类型先进行自动装箱,然后再向上转型
c1.add(1);
System.out.print(c1.isEmpty()); //前面将1放入c1中,不为空了, //false
System.out.println(c1.size()); //长度为1
c1.add("xxxx");
System.out.print(c1.size()); //前面将xxxx放入数组中,所以长度为2 //2
System.out.println("=====");
//转换为数组进行遍历
Object[] object=c1.toArray();
for(Object objects:object){
System.out.println(objects); //1 xxxx
}
//删除
c1.remove("xxxx");
System.out.println(c1.size()); //1
//清空集合
c1.clear();
System.out.println(c1.isEmpty()); // 空了,结果为true
}
}
注意
boolean contain(Object o);? 判断是否包含某个元素
Boolean remove(OBject o); 删除指定元素
这两个方法,底层都会调用equals方法进行比较
比如c.contain("abc"); 会用abc调用equals方法和集合中所有的元素进行比较
所以,如果我们要存储的是自定义的类型,比如User等,那么想要使用contains和remove就需要覆写equals方法
?
package day7_15;
import java.util.ArrayList;
import java.util.Collection;
/**
* boolean contains(Object o) : 判断是否包含某个元素
*
* boolean remove(Object o) : 删除指定元素
*
* 这两个方法,底层都会调用equals方法进行比较
*
* 比如 c.contains("abc") ; 会用abc调用equals方法和集合中所有的元素进行比较
*
* 所以 如果我们要存储的是自定义的类型,比如User等,那么想要使用contains和remove 就需要覆写equals方法
*
*
* @author 啊超
* @Date 2021年7月15日
*/
public class Collection_3 {
public static void main(String[] args){
Collection c=new ArrayList();
c.add(1);
c.add(new Integer(1));
System.out.println(c.size()); //2
Integer i1 = new Integer(1);
System.out.println(c.contains(i1)); //true 包含,默认调用tostring,euqals,比较的是值
Manager m1=new Manager(1,"张三");
Manager m2=new Manager(1,"张三");
c.add(m1);
System.out.println(c.contains(m1));
System.out.println(c.contains(m2));//object中默认比较地址,编号姓名一致,应该是同一个人,所以需要equals
}
}
class Manager{
public boolean equals(Object obj){ //这段就是equals的
if(this==obj){
return true;
}
if(obj instanceof Manager){//判断obj是否由Manager实例化而来
Manager m=(Manager)obj;// 强制类型转换
if(no==m.no&&name.equals(m.name)){
return true;
}
}
return false;
}
private int no;
private String name;
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;
}
}
Iterator
概述
? 1Collection接口的iterator()和toArray()方法都用于获得集合中的所有元素,前者返回一个Interator对象,后者返回一个包含集合中所有元素的数组。
? 2 Interator接口隐藏底层集合中的数据结构,提供遍历各种类型集合的统一接口。
for和iterator的对比
Iterator的好处在于可以使用相同方式去遍历集合中元素,而不用考虑集合类的内部实现
使用Iterator 来遍历集合中元素,那所有遍历此集合的算法,都得做相应调整,因为List有序,Set无序结构不同,他们的访问算法也不一样
for 循环需要下标
方法
使用
package day7_15;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
*
*
* 迭代器; 可以屏蔽底层数据存储的差异
*
* @author 啊超
* @Date 2021年7月15日
*/
public class Collection_2 {
public static void main(String[] args){
Collection c=new ArrayList();
c.add(1);
c.add("asd");
c.add("123");
c.add("avc");
c.add("xxx");
c.add(false);
//生成迭代器
Iterator it=c.iterator(); //这里是迭代器不能使用大写i,使用小写i
//迭代器一旦创建,集合中元素不能删除和添加,否则就需要重新生成迭代器
c.add("acf"); //in thread "main" java.util.ConcurrentModificationException异常
// 加上
it = c.iterator(); //重新生成迭代器 就可以了
System.out.println(c);
while(it.hasNext()){
Object object=it.next();
System.out.println(object);
//如果使用迭代器的过程中,需要进行删除,必须使用迭代器的remove方法
it.remove();
}
//迭代器遍历完之后,想再次遍历只能生成
it= c.iterator();
while(it.hasNext()){
Object object=it.next();
System.out.println(object);
}
}
}
List
List.有序可重复
存入顺序和取出顺序是一致的
ArrayList;底层是数组,查询和更改效率极高,添加和删除效率极低
LinledList;底层是双向链表,查询效率较低,添加删除效率极高
Vector ; 已经过时,底层也是数组,ArrayList是Vector的升级版
? ? ? ? ? ? ?Vector默认容量是10,扩大容量是2倍,线程安全,效率较低
? ? ? ? ? ? ?ArrayList默认容量是10,扩大容量是1.5倍,非线程安全,效率较高
ArrayList
package day7_15;
import java.util.ArrayList;
import java.util.Iterator;
/**
*
* List : 有序可重复
* 存入顺序和取出顺序是一致的
*
* ArrayList : 底层是数组,查询和更改效率极高,添加和删除效率较低
*
* LinkedList : 底层是双向链表,查询效率较低,添加删除效率较高
*
* Vector : 已经过时,底层也是数组,ArrayList是Vector的升级版
* Vector 默认容量是10,扩大容量是2倍,线程安全,效率较低
* ArrayList 默认容量是10,扩大容量是1.5倍,非线程安全,效率较高
*
* @author 啊超
* @Date 2021年7月15日
*/
public class Collection_4_List {
public static void main(String[] args){
//底层是Object[]数组,也就意味着只能保存引用类型
//但是由于基本类型会自动装箱为包装类类型,所以导致Object[]数组啥都可以往里放
ArrayList list=new ArrayList();
//将元素添加到列表尾部
list.add(11); //11
//将元素添加到指定位置 将22插入到0位上
list.add(0,22); //22,11
//替换指定位置上的元素
list.set(1,33); //22,33
//根据索引获取对应的元素
System.out.println(list.get(1)); //打印 1号位上的数字 //33
//根据索引删除元素
list.remove(1); //删掉1号位上的数 //结果为22
//删除指定元素,不能直接输入数字,直接输入的是下标,应该将想要删掉的数字进行包装
list.remove(new Integer(22)); //删掉数组中的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));
}
}
}
LinkedList
概述
LinkedList ;底层是双向链表
链表的节点有三个部分构成;1添加的元素(身体)? 2下一个节点的引用(放在尾部)? ? 3上一个节点的引用(放在头部)
链表数据结构,在内存中存储也不是连续的,所以没有固定的下标,因此查询效率低
因为内存空间不是连续的,只是能找到下一个节点,因此添加和删除就变得容易了
个人理解链表删除;假设有三个表,用a,b,c分别表示
a的尾部有指向b的地址,b的头部有个地址可以指向a的尾部,b的尾部有个指向c的头部地址,c的头部有个指向b尾部的指针。
如果要删除b这个表,那么,只需要将b尾部的指针放到a的尾部,那么a的尾部就可以找到c了,而将b的头部地址放到c的头部中,就可以让c找到a,这样就跳过了b,达到了删除的效果
基本使用
package day7_15;
import java.util.LinkedList;
/**
*
*
* LinkedList : 底层是双向链表
* 链表的节点 有三个部分构成 : 1 添加的元素 , 2 下一个节点的引用 , 3 上一个节点的引用
* 链表数据结构 , 在内存中存储也不是连续的,所以没有固定的下标,因此查询效率低
* 因为内存空间不是连续的,只是能找到下一个节点,因此添加和删除就变的容易了
*
* @author 啊超
* @Date 2021年7月15日
*/
public class Collection_5 {
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();
System.out.println(linkedList);
}
}
底层实现
?
?
|