JavaSE_集合

一、 概述

集合也是Java中的一种类,其作用和数组类似,都是用来存放数据的,不过底层结构和存放方式都有很大不同

二、集合与数组的区别

1.长度区别

数组:被创建时长度固定,后续不可进行改变;
集合:创建时未指定长度,根据使用情况动态改变长度;

2.存放类型区别

数组:可以存放基本数据类型,也可存放引用类型;类型在创建时固定;
集合:只能存放引用类型数据;存放类型为Object类型;

3.其他区别

数组length()只能判断长度,不可知其中实际存有多少元素;集合可通过size()得到元素个数;
数组存放元素只能通过顺序方式;集合根据底层结构,可以有更多选择;
集合以类的形式存在,可以进行更多的复杂操作

三、集合分类

JavaSE_集合_第1张图片

- Collection:单列集合类的根接口(List、Set)

特有方法:(继承此接口所有子类的共有方法)

  • .add() ——添加一个元素
  • .addAll() ——添加一组元素
  • .clear() ——清空集合
  • .remove() ——移除一个元素
  • .removeAll() ——移除一组元素
  • .contains() ——判断此元素是否存在
  • .isEmpty() ——判断集合是否为空
  • .size() ——获取集合中的元素个数

- Iterator:迭代器,用于取出Collection集合中的所有元素

	ArrayList li =new ArrayList();
	li.add("遗憾怎么了");
	li.add("遗憾怎么了了");
	li.add("遗憾怎么了了了");
	li.add("遗憾怎么了了了了");
	li.add("遗憾怎么了了了了了");
	//hasNext()判断集合下一个元素是否存在
	for(Iterator it = li.iterator();it.hasNext();)
	{
     
		System.out.println(it.next());
	}

- List:元素有序,元素可以重复;该集合有索引;

List集合可以对角标进行操作,因此具有一些特有方法

  • add(index,element) ——指定插入
  • remove(index) ——指定删除
  • set(index,element) ——指定修改
  • get(index) ——角标查询
  • subList(1,3) ——截取子串(含头不含尾,截取1,2)
	//常用遍历集合元素的方法
	for(int i = 0; i<arr.size();i++){
     
		sop("arr["+i+"]:"+arr.get(i));
	}

- ListIterator:List的特有迭代器,Iterator的子接口

因Iterator在使用中局限性太大,迭代时不能使用更改容器元素的指令,因此拓展了ListIterator的接口,用于在迭代中对元素进行操作

	ArrayList arr = new ArrayList();
	arr.add("wsf_001");
	arr.add("wsf_002");
	arr.add("wsf_003");
	arr.add("wsf_004");
	sop(arr);		
	for(Iterator it = arr.iterator();it.hasNext();){
     //Iterator迭代器无法在迭代时对集合进行更改
		Object obj = it.next();	//迭代器和容器方法不能并发
		if(obj.equals("wsf_003")){
     
			arr.add("wsf_0035");
		}
		sop("Iterator: "+obj);
	}
	for(ListIterator list = arr.listIterator();list.hasNext();){
     //可以在迭代中更改集合元素
		Object obj = list.next();
		if(obj.equals("wsf_003")){
     
			list.add("wsf_0035");//迭代器自身的方法添加元素
		}
		if(obj.equals("wsf_004")){
     
			list.set("wsf_0039");
		}
		if(obj.equals("wsf_001")){
     
			list.remove();
		}
		sop("ListIterator: "+obj);//打印的还是本来的元素,更改的是元素的引用
	}
	sop(arr);//更改成功
- ArrayList:

ArrayList的数据结构为数组,创建时初始长度为10,当集合装满后,以当前长度的50%进行延长

  • 特点:查询速度快,增删速度慢;线程不同步
  • 原因:数据结构为数组,查询时根据索引 寻找,速度快;当增加数据时(中间插入),需要先将插入点之后的数据逐个向后移一位,再进行插入;删除同理,删除后需要将删除点后的数据逐个向前移一位,因此增删的速度很慢;
  • 使用:ArrayList建议使用在单线程的环境下,可以用于存放一些以查询居多,不经常进行增删的数据
- LinkedList:

LinkedList的数据结构为链表结构

  • 特点:增删速度快,查询速度慢
  • 原因:LinkedList采用的是双向链表结构,当增删节点时,只需要改变前后两个节点的prev、next引用即可;但查询时,由于没有索引,只能通过遍历的方式,效率较低。
  • 特有方法:
	LinkedList link = new LinkedList();
	link.addFirst("wsf_001");//特有方法,首位添加
	link.addLast("wsf_004");//末尾添加
	link.getFirst();
	link.getLast();//取出首尾元素
	link.clear();
	sop(link);//link为空,抛出异常
	//新版本方法特性
	LinkedList link1 = new LinkedList();
	link1.offerFirst("wsf_001");//替代add
	link1.peekFirst();//替代get
	link1.peekLast();
	while(!link1.isEmpty()){
     
		sop("poll:"+link.pollFirst());//替代remove
	}
	link1.clear();
	sop("link empty:"+link.pollFirst());//新版本不再抛出异常,返回NULL

拓展:链表结构

  • 单向链表:
    链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始;结构简单
    JavaSE_集合_第2张图片
  • 双向链表
    每个数据结点中都有两个指针,分别指向直接后继和直接前驱;从双向链表中的任意一个结点开始,都可以很方便地访问前驱结点和后继结点JavaSE_集合_第3张图片
- Vector:

是List容器下的第三个分支,其大部分功能与ArrayList重合
独有特点:

  • 线程同步、安全
  • 空间100%增长,不节约空间
  • 特有方法:elements()——枚举
       Enumeration en = v.elements();
	   en.hasMoreElements();//判断下一个元素是否为空
	   en.nextElements();//获取下一个元素

- Set:元素无序,元素不能重复;

- HashSet

HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持。它不保证set 的迭代顺序;不保证该顺序恒久不变。此类允许使用null元素
HashSet是基于HashMap实现的,其储存的对象实际上是由HashMap的Key进行保存,因此其不可重复
元素不可重复的实现:

  • hashCode 和 equals
  • 系统类对象默认通过这两个值确认是否重复
  • 自定义对象需要在类中重写equals()、hashcode()方法
    原理:首先比较hashCode是否相同,若不同,判定为不同对象,若相同,继续比较equals(),若相同,判定为同一对象,不进行存入
    JavaSE_集合_第4张图片
    常用重写方法:
	//重写hashCode方法,使相同对象返回的哈希值是相同的,从而进入比较环节
	public int hashCode(){
     
		return name.hashCode()+age*2;
	}
	public boolean equals(Object obj){
     
		if(!(obj instanceof Ren)){
     
			return false;
		}
		//向下类型转换
		Ren r = (Ren)obj;
		//自定义比较方式
		return this.name.equals(r.name)&&this.age == r.age;
	}
- TreeSet

底层数据结构为二叉树,可以对元素进行排序
实现:通过元素比较性或者比较器,对元素进行排序

  • 1.自然排序,继承Comparable接口——重写方法compareTo(),元素必须具有比较性
@Date
class Car implements Comparable{
     
	private String name;
	private int price;
	public Car(String name,int price){
     
		this.name = name;
		this.price = price;
	}
	@Override
	public int compareTo(Object obj) {
     //重写比较方法,用价格进行排序
//		return 1;//无需判断,怎么存的,怎么取,-1为倒叙,0只留第一个
		if(!(obj instanceof Car)){
     
			throw new RuntimeException("不是学生对象");
		}
		Car c = (Car)obj;
		//决定了顺序或者是逆序
		if(this.price>c.price)
			return 1;
		if(this.price==c.price)
		{
     
			return this.name.compareTo(c.name);//主要条件排序过后,遇到相等的元素,继续排序次要条件;
		}	
		return -1;
	}
}
  • 2.比较器比较,通过比较类实现Comparator接口,覆盖compare()方法,制定比较规则
//比较器方法,新建类实现Comparator接口
class Mycompare implements Comparator{
     
	public int compare(Object o1, Object o2) {
     
		Car c1 = (Car)o1;
		Car c2 = (Car)o2;
		int num = c1.getName().compareTo(c2.getName());
		if(num == 0)//主条件重复,对次要条件进行比较,3种方式
		{
     
//			return c1.getPrice()-c2.getPrice(); //方法1,求差,最简便
			
			//方法二,逐个列出条件,最灵活
//			if(c1.getPrice()>c2.getPrice())
//				return 1;
//			if(c1.getPrice()==c2.getPrice())
//				return 0;
//				return -1;
			
			//方法三,因int对象Integer自身具有比较方法compareTo,因此将int转换为Integer后进行比较
			return new Integer(c1.getPrice()).compareTo(new Integer(c2.getPrice()));
			
		}
		return num;
	}
}

在新建集合时,加入比较器

TreeSet t = new TreeSet(new Mycompare());//加入比较器

比较器特点:使容器自身具备比较性,其优先级高于自然排序

Map

通过存入键值对,来存储对象,其中键的值唯一,不可重复
特有方法:

  • put(key,value)——添加(返回值:Value,键重复时,覆盖操作,并返回旧值)
  • putAll(Map)——添加全部
  • remove(Key)——删除
  • clear()——清空
  • containsValue(value)——判断value是否存在
  • containKey(key)——判断key是否存在
  • isEmpty——判断是否为空
  • get(key)——通过key获取值,不存在返回null
  • size() ——获取长度
  • values()——获取所有的值(没有键)
  • keySet()——将map转换为set,利用迭代器取出所有的键,再使用get获取所有值
	Map<String,String> map = new HashMap<String,String>();
	Set<String> set = map.keySet();
	Iterator<String> it = set.iterator();
	while(it.hasNext()){
     
		String k = it.next();
		String v = map.get(k);
		sop("key:"+k+"----value:"+v);
	}
  • entrySet()——存放键值对的映射关系
    通过内部接口Entry存放,并使用其特有方法getKey(),getValue()获取元素
		Set<Map.Entry<String, String>> set1 = map.entrySet();
		Iterator<Map.Entry<String, String>> it1 = set1.iterator();
		while(it1.hasNext()){
     
			Entry<String, String> m1 = it1.next();
			String k = m1.getKey();
			String v = m1.getValue();
			sop("key:"+k+"----value:"+v);
		}

- HashTable

HashTable底层为哈希表,功能和HashMap大致相似,有部分差异

  • 线程同步:很多方法都是用synchronized修饰,但同时因为加锁导致并发效率低下,单线程环境效率也十分低
  • 不可插入Null
    相比之下,HashMap的效率更快,因此在单线程情况下,已经取代了HashTable;

- HashMap

底层原理与HashSet相同,都是用的是哈希表数据结构,使用链表+数组的储存方式(防止哈希冲突)

  • 允许存入NULL
  • 线程不同步,用于单线程
  • 效率高(链表需要遍历,因此链表越少,效率越高)
  • 重复时覆盖

- TreeMap

底层原理与HashSet相同,底层为二叉树,用于给Map集合中的Key排序
实现方法与HashSet一致

你可能感兴趣的:(JavaSE,java)