集合大家庭

概述

与数组类似,用于存储多个数据的容器;

与数组的区别:

数组:类型相同,长度固定 集合:类型可以不同,长度不固定

数组可存基本类型或引用类型 集合只能存引用类型

数组不能调方法 集合是一个类,可调用方法操作元素

集合架构

集合是一个家族分为单列集合和双列集合,单列集合最大的根接口为Collection;下面所有的集合类或接口都是它的子接口或实现类

Collection有两个重要的子接口: List,Set

List接口下面有两个重要的实现类:ArrayList,LinkedList

Set接口下面的两个重要的实现类:HashSet, TreeSet

List接口存储特点:存储元素有下标,有序,可重复

Set接口存储特点:存储元素无下标,无序,唯一

单列集合

Collection

单列集合最大的根接口,特点是无下标

基本用法

Collection col = new ArrayList();
col.add(1);  //添加元素  自动装箱--Integer
col.add(3.5);  //Double
col.add(2);
System.out.println(col);  //[1, 3.5, 2]

Collection col2 = new ArrayList();
col2.add(6);
col.addAll(col2);  //添加集合
System.out.println(col);  //[1, 3.5, 2, 6]

col2.clear();  //清空元素
System.out.println(col2);  //[]
System.out.println(col.contains(3.5)); //true  判断集合中是否包含指定元素
System.out.println(col.equals(1));  //false  判断集合元素是否相等
System.out.println(col.isEmpty());  //false  判断集合是否为空
System.out.println(col.remove(2));  //true   移除指定元素
System.out.println(col);
System.out.println(col.size());  //获取集合元素个数
Object[] o = col.toArray();   //集合转数组
System.out.println(Arrays.toString(o)); 

循环遍历

//Colletion循环遍历:
Collection col = new ArrayList();
col.add(1);
col.add(3);
col.add(2);
//1.基本for--操作下标,不可以;无下标
for(int i=0;i<col.size();i++) {}

//2.增强for  foreach
for (Object obj : col) { //本质是迭代器-查反编译工具
    System.out.println(obj);
}
System.out.println("========");
//3.迭代器 
Iterator it = col.iterator();
while(it.hasNext()) { //判断是否有下一个元素
    System.out.println(it.next());  //有则取出,并移位 
}

List

List集合是Collection的子接口,在Collection标准基础上,扩充了一些与下标操作相关的方法

存储元素特点:有序,有下标,允许重复

基本用法

//List的基本操作及存储特点:
List list = new ArrayList(); //ArrayList是List的实现类
list.add(1);
list.add(3);
list.add(2);
list.add(2);  //允许重复
System.out.println(list); //1,3,2,2 有序

list.add(1, 666); //指定下标位置添加元素
System.out.println(list);
List list2 = new ArrayList();
list2.add(5);
list.addAll(1, list2); //指定位置存集合
System.out.println(list);

System.out.println(list.get(2)); //根据下标取元素
list.set(2, 999);  //指定位置的修改
System.out.println(list);

List list3 = list.subList(1, 3); //提取子集合
System.out.println(list3); //根据开始和结束下标提取集合,不包括结束下标

//除以上方法外,Collection接口中提供的方法依然能用
list.remove(0); //根据下标移除
System.out.println(list);

循环遍历

//List循环遍历:
List list = new ArrayList();
list.add(1);
list.add(3);
list.add(2);
//1.基本for
for(int i=0;i<list.size();i++) {
    System.out.println(list.get(i));
}
System.out.println("==========");
//2.增强for
for (Object o : list) {
    System.out.println(o);
}
System.out.println("=====ListIterator(扩展)=====");
ListIterator li = list.listIterator();  //有迭代器功能和反向遍历
while(li.hasNext()) { //判断是否有下一个
    System.out.println(li.next());  //有下一个则取出
}
System.out.println("-----------");
while(li.hasPrevious()) { //判断是否有上一个(在迭代器指向最后,才能用)
    System.out.println(li.previous()); //取出后,指向上一个
}

ArrayList与LinkedList

List有两个重要的实现类,ArrayList和LinkedList,他们的存储特点都是一致的,调用方法也相同;但是存储原理不同

ArrayList

存储原理:通过数组扩容方式进行存储

细化原理:当存储第一个元素,内部开是个数组空间用于存元素;当没空间了,则进行扩容,并拷贝原数组值,每次扩当前元素的一半。

通过画图分析+原码分析,理解ArrayList的存储原理

说明:数组是连续的空间,本身有下标标记,很容易就找到下标的元素

LinkedList

存储原理:通过双向链表方式存储

细化原理:每次存值,都开空间节点,准备三个属性,pre,data,next;data存值,pre节点指向上一个节点,next指向下一个节点;当存储第二个值,开空间,并将旧节点的next执行新节点,新节点的pre指向上一个节点;这样就构成了双向链表。

通过画图分析+原码分析,理解LinkedList的存储原理

说明:链表的空间不连续,通过上一个或下一个节点的指向去定位元素

区别

在List接口中上面的两个实现类都可以完成存储数据的功能,除了存储功能,还有删除,查找,修改等功能,分析两个实现类的性能。

  1. 添加

    向后追加:ArrayList和LinekdList都需要开空间,ArrayList稍快

    指定位置追加:ArrayList考虑集体搬迁 PK LinkedList考虑定位(快)

  2. 删除(下标删)

    与指定位置追加类似,ArrayList要集体搬迁 ,LinkedList要定位;LinkedList快

  3. 查找

    查找就是定位;数组是连续内存空间,本身有下标标记,所以定位快;ArrayList快

  4. 修改

    修改=查找+赋值;ArrayList快

结论:后续常用ArrayList,因为常用操作是查找和向后追加

Set

Set接口:Collection的子接口,Set接口没有提供抽象方法,全部继承Collection

Set的特点:无序、无下标,唯一

HashSet

存储特点:无序,无下标,唯一

HashSet存储方式:hash算法+数组+链表

细化原理:

存储的对象要得到hash值,hash值在hash表中(数组)得到一个下标位置;判断该下标位置是否有值,如果没有则直接存储;如果有,与该位置的链表元素一一比较;如果相等,则退出,确定唯一性;如果都不相等,则存储到该链表中。

分析规则: 画图分析+原码分析

结论:存储的元素要确定唯一性,则必须重写hashCode和equals

//基本使用:
Set<Integer> set = new HashSet<Integer>();
set.add(11);
set.add(33);
set.add(22);
set.add(22);  //唯一
System.out.println(set);  //HashSet特点:无序,唯一
//Set是Collection的子接口,所以Collection的常用方法,Set可完全继承

//循环遍历:1.基本for   无下标,不能使用
//for(int i=0;i<set.size();i++) {}

//增强for:有增强for,所以肯定有迭代器
for (Integer integer : set) {
    System.out.println(integer);
}

TreeSet

存储特点:可排序,无下标,唯一

TreeSet的存储方式:二叉树

细化原理:存第一个元素时,作为根节点;再次存储,则于根比较;比根大则放右边,比根小放左边;查看左/右子树是否有节点,如果没有,则直接存;如果有节点,则继续比较;依次类推;如果找到相等的,则退出,确定唯一性;否则,比较到最后,存进来。

分析规则:画图分析+源码分析

结论:存自定义对象主要要看比较的规则:1.自然排序法(Comparable接口) 2.比较器法

//TreeSet基本应用
Set<Integer> set = new TreeSet<Integer>();
set.add(11);
set.add(33);
set.add(22);
set.add(22);
System.out.println(set);  //[11, 22, 33]  可排序,唯一

//循环遍历:  1.基本for--没有基本for(无下标)
//for(int i=0;i<set.size();i++) {}

//2.增强for  可以有--迭代器一样也有
for (Integer integer : set) {
    System.out.println(integer);
}

因为TreeSet具有可排序的特点,所以可以根据自定义的对象所具有的属性进行对数据的排序

//自定义类为一个属性的情况:
//说明:存储自定义对象,自定义类要么实现Comparable接口;要么使用比较器
class Student implements Comparable<Student>{
	String name;
	public Student(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + "]";
	}
	@Override
	public int compareTo(Student o) { //重写的比较方法中,只要返回结果于源码对应上即可
		//将对象的比较,转成属性的比较
		//String的compareTo:前面的小返回<0  前面的大则返回>0  相等则返回0
		//return this.name.compareTo(o.name); //返回<0则存左子树;>0则存右子树;=0唯一性
		
		return o.name.compareTo(this.name);  //比较规则反过来则是降序排列
	}
} 
public class Test2 {
	public static void main(String[] args) {
		Set<Student> set = new TreeSet<Student>();
		set.add(new Student("zs"));
		//ClassCastException: Student cannot be cast to Comparable
		set.add(new Student("ls"));
		set.add(new Student("ww"));
		set.add(new Student("zs"));
		
		System.out.println(set);
	}
}

双列集合

Map

概述:和Collection同级的根接口,Collection子孙类都是存单个对象;Map接口子孙类存的都是两个对象(键值对)

应用场景:往往key是已知的(基本上key是String类型),value是未知的; 后续我们需要去配置文件中取值,key就是已知字符串;值是我们可以随意更换

Map接口有两个重要的实现类: HashMap,TreeMap; 此外还有Hashtable,Properties

 HashMap

描述:HashMap是Map接口的实现类,集合中存储键值对

存储特点:key无序,无下标,唯一; 确定唯一性后,后面的value会覆盖前面的。

HashMap的存储原理与HashSet是类似的,都是通过hash算法+数组+链表的方式

直接分析源码即可得出结论

结论:存储key的类要重写hashCode和equals才能确定唯一性

//HashMap的基本应用:
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("aa", 666);
map.put("cc", 999);
map.put("bb", 666);
map.put("bb", 999);  //key无序,唯一;key相等后,value会覆盖前面的
System.out.println(map);

System.out.println(map.get("cc")); //根据key获取value值

Collection<Integer> col = map.values(); //将所有value放入Collection集合
System.out.println(col);

//循环遍历:1.基本for---不行,无下标
//for(int i=0;i<map.size();i++) {}

//增强for: 不行,没有统一的类型;  迭代器也不行
//for(String key :map) {}

//只能间接循环: keySet   entrySet
//1.keySet:将所有key放入Set集合,然后循环根据key遍历出value
Set<String> set = map.keySet();
for (String key : set) {
    System.out.println(key+"--"+map.get(key));
}
System.out.println("=======================");
//2.entrySet:将键值对作为实体存到Set;再循环Set取出实体拿出里面的键值对
Set<Entry<String, Integer>> entries = map.entrySet();
for(Entry<String, Integer> entry:entries) {
    System.out.println(entry.getKey()+"=="+entry.getValue());
}

 

TreeMap

TreeMap的存储特点:key可排序,唯一; 确定唯一后,后面的值覆盖前面的

存储原理:通过二叉树存储

TreeMap的实现原理与TreeSet类似的,此处得出结论即可

结论:要有比较的规则:自然排序法(实现Comparable接口)

//TreeMap的基本应用:
Map<String, Integer> map  = new TreeMap<String, Integer>();
map.put("aa", 11);
map.put("cc", 11);
map.put("bb", 11);
map.put("aa", 66);
System.out.println(map);   //3
System.out.println(map.get("cc"));  //根据key获取value

//循环遍历:keySet,entrySet
Set<String> set = map.keySet();
for(String key:set) {
    System.out.println(key+"=="+map.get(key));
}
System.out.println("-----------------");
Set<Entry<String, Integer>> ens = map.entrySet();
for(Entry<String, Integer> entry:ens) {
    System.out.println(entry.getKey()+"--"+entry.getValue());
}

Map的选择

HashMap与TreeMap的比较:

  1. 优先选择HashMap,因为性能更高

  2. 除非需要排序,才选择TreeMap; HashSet与TreeSet也类似

应用案例

案例:有一个字符串,求出每个字符串的个数: “ddcada”; 得出结果:d--3 a--2 c--1

分析:需要用到键值对,选择Map集合;没有排序的要求,则使用HashMap存储

//案例:有一个字符串,求出每个字符串的个数:  “ddcada”; 得出结果:d--3   a--2   c--1
String a = "ddcada";  //将字符串转字符数组,再循环遍历
char[] cs = a.toCharArray();

Map<Character, Integer> map = new HashMap<>();//key为字符  值为次数
for(int i=0;i<cs.length;i++) {
    Integer count = map.get(cs[i]); //根据key获取value; 没有则返回null
    if(count==null) { //为空
        map.put(cs[i], 1); //存储1个
    }else { //不为null,次数+1
        map.put(cs[i], count+1);
    }
}
System.out.println(map);

集合汇总

Collection  VS  Map:          存单个对象             存键值对
Collections  VS Collection:  工具类                 集合接口  
List   VS    Set:            有序,有下标,可重复     无序,无下标唯一
ArrayList VS  LinkedList      数组扩容;查询修改快     双向链表; 增删快
Set   VS   Map                单个对象               存键值对
HashSet  VS   HashMap         对象无序,唯一          key无序唯一; 两者原理一致;具体实现Map完成
TreeSet  VS   TreeMap         对象可排序,唯一        key可排序唯一;两者原理一致;具体实现Map完成
HashSet  VS   TreeSet         对象无序,唯一          对象可排序唯一
HashMap  VS   TreeMa

p         key无序,唯一          key可排序唯一 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值