java的集合框架ListSetMap

什么是集合?

存储多个对象的单一对象(java容器)。

为什么不用数组?

集合与数组都是对数据进行存储操作的结构,简称java容器。
此时的存储主要是内存方面的,不涉及到持久话存储(.txt,.jpg,数据库)。
数组存储的缺点:
1、一但初始化,长度确定。
2、数组创建后,元素类型确定。
3、数组提供的方法有限。
4、数组不能够存储无序,不可重复的数据。

集合框架

集合框架有两个父接口:Collection和Map 和 Collections工具类。
集合框架体系

一、父接口Collection

单列集合,用来存储一个一个的对象。

向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals方法。

方法简介
add(object obj)将元素obj添加到集合当中
size()获得添加元素的个数
addAll(Collection collection1)将集合collection1,添加到原有集合中
isEmpty()判断当前集合是否为空
clear()清空集合元素
boolean remove(object obj)通过元素的equals方法找到要删除的元素,并且只会删除找到的第一个元素
boolean removeAll(Collection coll)取当前集合的差集
boolean retainAll(Collection coll)把交集的结果存储到当前集合中,不影响coll
boolean equals(Object obj)判断集合元素是否相等
Object[] toArray()转成对象数组
hashcode()获取集合对象的哈希值
contains(Object obj)判断集合对象中是否包含obj,判断时会调用obj对象所在类的equals方法
containsAll(Collection coll)判断coll中元素是否都存在与当前集合中

集合—>数组

Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(789);
Object[] arr = coll.toArray();

数组—>集合

List<String> list = Arrays.asList(new String[] {"aa","bb","cc"});
//不能进行增删操作:因为转成的集合对象是Arrays里内部类的ArrayList,不是集合框架中的ArrayList。

//如果想要进行增删操作,需要新建一个集合对象。
List<String> list1 = new ArrayList<String>(list);

Collection集合对象遍历

Collection接口继承了java.lang.Iterable接口,该接口中有一个Iterator()方法。

迭代器Iterator

1、iterator只适用于遍历,它本身不具备承载对象的能力。如果需要创建迭代器对象,必须要先有一个被迭代的集合。

Collection coll = new ArrayList();
		coll.add(123);
		coll.add(234);
		coll.add("AA");
		Iterator it = coll.iterator();
		while(it.hasNext()) {
			Object obj = it.next();
			System.out.println(obj);

2、集合对象每次调用iterator都会得到一个全新的迭代器对象。默认的游标在集合第一个元素之前。
3、在迭代过程中,迭代器可以通过remove()方法删除集合中的元素,此remove并非是集合框架中的remove()方法。
4、如果在未调用next()方法之前或再之后调用两次remove(),调用remove方法,会报IllegalStateException

Collection coll = new ArrayList();
		coll.add(123);
		coll.add(234);
		coll.add("AA");
		Iterator it = coll.iterator();
		//hasNext():判断是否还有下一个元素
		while(it.hasNext()) {
			//next():1、指针下移 2、将下移后集合位置上的元素返回
			Object obj = it.next();
			if(obj.equals("AA")) {
				it.remove();
			}
		}
		Iterator it1 = coll.iterator();
		while(it1.hasNext()) {
			System.out.println(it1.next());
		}
foreach遍历

java5.0提供了foreach(增强for循环),可以对集合和数组进行遍历。
增强for循环底层仍然调用了iterator

for(遍历的元素类型 遍历元素的自定义名称:遍历结构名称){
	System.out.println(遍历元素的自定义名称);
}

常规for循环也可以实现集合的遍历

二、Collection的子接口1:List

List接口概述

1、鉴于java数组存储数据的局限性,通常使用List代替数组。
2、List集合中的元素有序,且可重复,集合中每个元素都有其对应的顺序索引–>常称为动态数组。
3、List的常用实现类有ArrayList,linkedList,Vector。_

ArrayList

List接口的主要实现类,线程不安全的,效率高。底层使用的是数组:Objec[] elementData存储。

LinkedList

对于频繁的删除,插入操作,LinkedList要比ArrayList效率要高,因为它的底层是双向链表存储,内部没有声明数组。线程也是不安全的。

Vector

作为List接口的古老实现类,它的线程是安全的,效率低。底层使用的是数组:Objec[] elementData存储。

List接口的常用方法

List除了继承了Collection方法外,List还添加了一些对于索引操作的方法。

方法简介
void add(int index,Object ele)在index处插入ele元素
boolean addAll(int index,Collection eles)在index处开始将eles集合中所有元素插入
Object get(int index)获取索引为index的元素
int indexof(Object obj)返回obj在集合中首次出现的位置,不存在返回-1
int lastIndexOf(Object obj)返回obj在集合中末次出现的位置,不存在返回-1
Object remove(int index)删除下标为index的集合元素,并返回此元素
Object set(int index,Object ele)设置index位置的元素为ele
List subList(int fromIndex,int toIndex)返回fromIndex到toIndex位置的子集合
List的遍历

1、迭代器Iterator

ArrayList list = new ArrayList();
		list.add(123);//自动装箱
		list.add(456);
		list.add("AA");
		Iterator it = list.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}

2、增强for循环

for(Object obj:list) {
			System.out.println(obj);
		}

3、普通for循环

for(int i=0;i<list.size();i++) {
			System.out.println(list.get(i));
		}
区分remove(int index)和remove(Object obj)
public static void main(String[] args) {
		ArrayList list = new ArrayList();
		list.add(1);//自动装箱
		list.add(2);
		list.add(3);
		updataList(list);
		System.out.println(list);
	}

	private static void updataList(ArrayList list) {
		list.remove(2);//这里的2指的是index
		list.remove(new Integer(2));//这里的2指的是对象
		
	}

三、Collection子接口2:Set

使用Set集合,必须重写元素所在类的hashcode()和equals()方法。

Set接口概述

1、Set接口是Collection的子接口,并没有提供额外的方法。
2、Set接口存储无序,且不可重复的数据。
3、Set接口判断数据是否重复不使用 “==”,而是equals方法。
4、Set的常用实现类:HashSet,LinkedHashSet,TreeSet。

HashSet

HashSet作为Set的主要实现类,线程不安全,可以存储NULL值。底层:数组+链表。

LinkedHashSet

做遍历操作时,可以按照添加的顺序遍历。

TreeSet

可以按照添加对象的指定属性进行排序。不能够添加所属不同类的对象。
底层采用红黑树结构,有序,查询速度比List快。

不可重复性与无序性描述

1、无序性!=随机性

所谓无序性是指,存储的数据在底层数组中并非按照索引顺序添加。而是根据数据的哈希值进行添加。

public static void main(String[] args) {
		Set set = new HashSet();
		set.add(123);
		set.add(456);
		set.add("AA");
		set.add("BB");
		System.out.println(set);
		
	}
以上代码第一次运行结果:[AA, BB, 456, 123]
           第二次运行:[AA, BB, 456, 123]

2、不可重复性

保证添加的元素按照equals判断时,不能返回true。即:相同的元素只能添加一个。

Set的存储过程

以HashSet为例:
		向HashSet集合添加元素a,首先调用a所在类的hashcode()方法,计算元素a的hash值。
		此哈希值接着通过某种算法计算出HashSet底层数组的存放位置(即,索引位置),判断
		数组此位置上是否有元素:
				如果此位置上没有其他元素,则a元素添加成功。
				如果此位置上其他元素b(或以链表形式存在多个元素),则比较元素a与元素b的哈希值:
						如果hash值不相同,添加成功。
						如果hash值相同,进而需要调用a所在类的equals()方法:
								equals()返回true,元素a添加失败。
								equals()返回false,元素添加成功。

在添加元素a时,若此位置上有其他元素b或多个元素,那么在这个索引位置的元素以链表结构存储:
	jdk7:元素a放到数组中,指向原来元素。如图1-2。
	jdk8:原来的元素在数组中,指向元素a。如图1-3。
	口诀:七上八下

存储流程图
在这里插入图片描述
图片1-2
图片1-2
图片1-3
1-3

LinkedHashSet无序性论证

在添加元素时,每个数据还维护了两个引用,记录此数据前一个数据位置和 后一个数据位置。实际存储的还是无序的。
对于频繁的遍历操作,LinkedHashSet效率高于HashSet。
在这里插入图片描述

TreeSet排序

自然排序(Comparable)

在自然排序中,比较两个对象是否相同的标准为:CompareTo()返回0,不再是equals()。

例子1:

public static void main(String[] args) {
		TreeSet set = new TreeSet();
		set.add(13);
		set.add(-56);
		set.add(5);
		set.add(56);
		System.out.println(set);
		
	}
结果为[-56, 5, 13, 56]    即,从小到大排序。

例子2:
按照姓名排序,元素所在类需要实现comparable接口,重写compareTo()方法。

TreeSet set = new TreeSet();
		set.add(new User("jack",14));
		set.add(new User("kite",14));
		set.add(new User("jom",14));
		set.add(new User("tonny",14));
		Iterator it = set.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
结果:	User [name=jack, age=14]
		User [name=jom, age=14]
		User [name=kite, age=14]
		User [name=tonny, age=14]

元素所在类compareTo():

public int compareTo(Object o) {
		if(o instanceof User) {
			User user = (User)o;
			return this.name.compareTo(user.name);
		}else {
			throw new RuntimeException("输入类型不匹配");
		}
		
	}
定制排序(Comparator)

需要创建comparator对象。
在自然排序中,比较两个对象是否相同的标准为:Compare()返回0,不再是equals()。

public static void main(String[] args) {
		Comparator com = new Comparator() {
			//年龄从小到大排列
			@Override
			public int compare(Object o1, Object o2) {
				if(o1 instanceof User && o2 instanceof User) {
					User u1 = (User)o1;
					User u2 = (User)o2;
					return Integer.compare(u1.getAge(), u2.getAge());
				}else{
					throw new RuntimeException("输入数据类型不匹配");
				}
			}
		};
		TreeSet set = new TreeSet(com);//不加com,按照自然排序
		set.add(new User("jack",14));
		set.add(new User("kite",52));
		set.add(new User("jom",19));
		set.add(new User("tonny",1));
		Iterator it = set.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
	}

四、Map接口

双列数据,存储key-value对数据。存储无序的双列数据。
key所在的类,需要重写hashcode()和equals()方法。
value所在的类,需要重写equals()方法。

Map实现类的对比

HashMap:作为map的主要实现类;线程不安全,效率高,存储null的key和value,底层:数组+链表(jdk7及之前),数组+链表+红黑树(jdk8)。

LinkedHashMap:在遍历map元素时,可以按照添加顺序进行遍历。

原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个元素和后一个元素。
	  对于频繁的遍历操作,效率高于HashMap。

TreeMap:按照添加的key-value对进行排序(按照key排序),实现排序遍历,考虑key的定制排序或自然排序。底层是红黑树。
HashTable:作为古老的实现类,线程安全,效率低,不能存储null的key和value。
Properties:HashTable的子类,常用来处理配置文件,key和value都是String类型。

Map结构

key:无序的,不可重复的,使用Set存储所有key。
value:无序的,可重复的,使用Collection存储所有value。
一个键值对:key-value构成了一个Entry对象,Entry:无序的,不可重复,使用Set存储。

Map接口的常用方法

增删改简介
Object put(Object key,Object value)将指定key-value添加/修改 当前mao对象中
void putAll(Map m)将m中的key-value对存放到当前map中
Object remove(Object key)移除指定key的key-value对,并返回value
void clear()清空当前map中的所有数据
查询简介
Object get(Object key)获取指定key对应的value
boolean containsKey(Object key)是否包含指定的key
boolean containsValue(Object value)是否包含指定的value
int size()返回map中key-value对的个数
boolean isEmpty()判断当前map是否为空
boolean equals(Object obj)判断当前map和参数对象obj是否相等
元视图操作简介
Set keySet()返回所有key构成的Set集合
Collection values()返回所有value构成的Collection集合
Set entrySet()返回所有key-value对构成的Set集合

HashMap的底层实现原理

jdk7:

HashMap map = new HashMap();
在实例化后,底层创建了一个长度为16的一维数组Entry[] table.
....
map.put(key,value);
....
首先,调用key所在类的hashcode()计算key的hash值,此hash值通过某种算法计算以后,得到在Entry数组中存放的位置。
如果此位置上的数据为空,此时的key-value添加成功。
如果此位置上的数据不为空,(意味着此位置上存在一个或者多个数据(以链表形式存在)),比较key和已经存在的一个或多个数据的hash值:
		如果key的hash值与已经存在数据的hash值都不相同,此时key-value添加成功。
		如果key的hash值与已经存在某个数据的hash值相同,调用key所在类的equals():
				如果equals()返回false:此时key-value添加成功。
				如果equals()返回true:将value替换原来的数据。
在不断添加的过程中,会涉及到扩容问题,默认的扩容方式为:扩容为原来容量的2倍,并将原来的数据复制过来。

jdk8相较于jdk7在底层实现方面的不同:
1、new HashMap():底层没有创建一个长度为16的数组。
2、jdk8底层数组是:Node[],而非Entry[]。
3、首次调用put()方法时,底层创建长度为16的数组。
4、
jdk7底层结构只 有:数组+链表。jdk8底层结构:数组+链表+红黑树。
当数组的某一个索引位置上的元素以链表形式存在的数据个数 >8 且当前数组长度 >64 时,此时此索引位置上的所有数据改为使用红黑树存储。

HashMap遍历

	public static void main(String[] args) {
			HashMap map = new HashMap();
			map.put("a", 15);
			map.put(12, 32);
			map.put("s", "aa");
			map.put("S", "kk");
			//遍历所有key集:keySet()
			Set set = map.keySet();
			Iterator it = set.iterator();
			while(it.hasNext()) {
				System.out.println(it.next());
			}
			//遍历所有value集:values()
			Collection values = map.values();
			for(Object obj:values) {
				System.out.println(obj);
			}
			//遍历所有key-value(Entry)
			Set EntrySet = map.entrySet();
			Iterator it1 = EntrySet.iterator();
			while(it1.hasNext()) {
				Object obj = it1.next();
				//entrySet集合中的元素都是entry
				Map.Entry entry = (Map.Entry) obj;//Map.Entry是Map的内部接口
				System.out.println(entry.getKey()+","+entry.getValue());
			}
	}

TreeMap排序

向TreeMap中添加的key-value,要求key必须有同一个类创建。
用key进行排序,自然排序与定制排序。详见TreeSet。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值