【java的集合框架】
Collection:
1.List
①ArrayList
②LinkedList
2.set
①HashSet
②LinkedHashSet
③TreeSet
Map:
1.HashMap
2.LinkedHashMap
3.TreeMap
4.HashTable
[四个接口的区别]
1.collection: 存储不唯一,无序的数据;
2.list: 存储有序的,不唯一的数据;
3.set: 存储无序的,唯一的数据;
4.map: 以键值对的形式存储数据,以键取值,键不能重复,值可以重复。
[list接口]
常用方法:
1.isEmpty() :判断列表是否为空,是为true。
2.clear() :清除列表中的所有数据
3.size() :返回当前元素的个数;
4.toArray() 返回包含所有元素的object类型的数组。
5.subList(fromindex,toindex) 返回一个左闭右开的List列表。
6..iterator(index): 从输入下标开始,返回一个列表迭代器。
7.get(int index) :返回下标为index的元素。
8.set(index,element)用此元素替换指定坐标的元素。
9.add() :在列表的最后添加元素。
add(index , element) :在指定位置插入元素。
addAll():在列表的最后添加集合。
addAll(index,collection) :在指定位置插入集合。
10.contains() :判断是否包含某元素。如果是 返回true;
如果传入的是String和基本数据类型,可以直接比对;
如果传入的是实体对象,则默认只对比两个对象的地址,因此需要在实体类重写equals()方法。
重写方法后,根据方法定义的判定条件来比对。
11.indexOf() :返回此列表中指定元素的第一次出现的坐标;
.lastIndexOf();返回最后一次出现的坐标。
如果传入的是实体对象,则默认只对比两个对象的地址,因此需要在实体类重写equals()方法。
重写方法后,根据方法定义的判定条件来比对。
12.remove() :传入一个下标或一个对象,删除该列表中指定位置的元素。 返回true和false,显示删除是否成功。
如果传入的是实体对象,则默认只对比两个对象的地址,因此需要在实体类重写equals()方法。
重写方法后,根据方法定义的判定条件来比对。
[ 使用iterator遍历列表]
1.使用列表调用.iterator()方法返回一个迭代器对象;
2.使用迭代器对象调用.hasNext()方法判断是否有下一条数据;
3.使用迭代器对象调用.next()方法输出下一条数据
Itreator<News> iter = list1.iterator(); while(iter.hasNext()){ News news=iter.next(); system.out.print(news); }
[ArrayList和LinkList的区别]
ArrayList:
实现了一个长度可变的数组,在内存空间中开辟了一串连续的空间,与数组的区别在于长度可以随意更改;
这种存储结构,在循环遍历和随机访问元素的速度比较快。
LInkList:
使用链表结构存储数据,在插入和删除元素时速度非常快。
特有方法:
1.addFirst() :开头插入元素;
2.addLast() :结尾插入元素;
3.removeFirst():删除一个元素,并返回被删除的元素;
.removeLast() :删除最后一个元素,并且返回被删除的元素。
4.getFirst() :返回第一个元素;
.getLast():返回最后一个元素。
>>>实体类重写 equals方法。
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; news other = (news) obj; if (a == null) { if (other.a != null) return false; } else if (!a.equals(other.a)) return false; if (id != other.id) return false; return true; }
[set接口]
1.常用方法,与list接口基本相同;
但是,由于set接口中的元素时无序的,因此没有与下标 相关的方法。
例如: get(index) remove(index) add(index,obj)...
2.Hashset 底层是调用HashMap的put方法,传入数据的数据为map的key,值为new object(),
将key转换成Hashcode,然后将Hashcode通过散列运算。
计算出一个散列值,再通过散列值计算出元素在序列中存储的位置。
[Hashset如何确定一个对象是否相等?]
①先判断Hashcode,如果Hashcode不同,肯定不是一个对象。
如果Hashcode相同,那继续通过equals()方法判断。
②重写equals方法。
所以,使用Hashset 存储实体对象时,必须重写对象的hashcode()和equals两个方法;
3.LinkedHashSet : 在HashSet的基础上,新增了一个链表;
用链表记录HashSet存入的顺序,因此使用迭代器遍历时,可以按照输入的顺序输出。
4.TreeSet,将传入的元素通过二叉树进行排序,
如果传入的是对象,那么实体类必须实现comparable接口,并且重写compareTo()方法。
如果对象传入空参构造,那么实体类需要实现comparable接口
或者在构造的同时,直接传入比较器(一个实现了comparator接口并重写了compare方法的实现类的对象)
使用匿名内部类 拿到一个比较器对象:
Set<Person> set1 =new TreeSet<Person>(new Comparator<Person>(){ @Override public int compare(Person o1, Person o2) { return o1.id-o2.id; } });
[Comparabale接口与Comparator接口的区别]
1.Comparable由实体类实现,重写 compareTo()实现;
实体类实现comparable接口以后,Treeset使用空参构造即可;
[Map接口]
1. Map特点:以 键 值 的方式存储。
键不可重复,值可重复。
2.常用方法:
1.put(key,value) :传入一个键 值 对;
2.get(key): 取得对应键的值。
3.containskey(obj):检测是否包含指定的键;
.containsvalue(obj):检测是否包含指定的值;
如果传入的是对象,重写hashcode和equals方法;
4.remove(key,value):删除指定的键值对;
5.replace(K key, V value)
.replace(K key, V oldValue, V newValue):仅当key和 oldvalue都匹配时,才用新value替换旧value;
6.values() :返回所有值的collection类型的集合。
7.keySet():返回所有键的set类的集合;
8.entrySet():返回所有键的entry泛型的set类集合。
8.clear() :清除所有数据。
[TreeMap]
根据键的顺序进行排序后,输出。
如果输入的是对象,参考TreeSet。
[HashMap和LinkHashMap的区别]
HashMap根据键排序,
LinkedHashMap根据输入顺序排序。
[HashMap与Hashtable的区别]
1.两者最主要的区别在于Hashtable是线程安全,而HashMap则非线程安全。
Hashtable的实现方法里面都添加了synchronized关键字来确保线程同步,因此相对而言HashMap性能会高一些,
我们平时使用时若无特殊需求建议使用HashMap
,在多线程环境下若使用HashMap需要使用Collections.synchronizedMap()方法来获取一个线程安全的集合
(Collections.synchronizedMap()实现原理是Collections定义了一个SynchronizedMap的内部类,
这个类实现了Map接口,在调用方法时使用synchronized来保证线程同步,当然了实际上操作的还是我们传入的HashMap实例,
简单的说就是Collections.synchronizedMap()方法帮我们在操作HashMap时自动添加了synchronized来实现线程同步,
类似的其它Collections.synchronizedXX方法也是类似原理。
2.HashMap可以使用null作为key,不过建议还是尽量避免这样使用。HashMap以null作为key时,总是存储在table数组的第一个节点上。而Hashtable则不允许null作为key。
3.HashMap继承了AbstractMap,HashTable继承Dictionary抽象类,两者均实现Map接口。
4.HashMap的初始容量为16,Hashtable初始容量为11,两者的填充因子默认都是0.75。
5.HashMap扩容时是当前容量翻倍即:capacity*2,Hashtable扩容时是容量翻倍+1即:capacity*2+1。
6.两者计算hash的方法不同:
Hashtable计算hash是直接使用key的hashcode对table数组的长度直接进行取模:
HashMap计算hash对key的hashcode进行了二次hash,以获得更好的散列值,然后对table数组长度取摸:
7.判断是否含有某个键
在HashMap 中,null 可以作为键,这样的键只有一个;可以有一个或多个键所对
应的值为null。当get()方法返回null 值时,既可以表示HashMap 中没有该键,也可
以表示该键所对应的值为null。因此,在HashMap 中不能用get()方法来判断HashM
ap 中是否存在某个键,而应该用containsKey()方法来判断。Hashtable 的键值都不能
为null,所以可以用get()方法来判断是否含有某个键。
>>>HashMap和Hashtable的底层实现都是数组+链表结构实现。
[遍历Map的三种方式]
遍历Map的第一种方式:.ksySet()
Set<String> keys=map1.keySet(); Iterator<String> iter1= keys.iterator(); while(iter1.hasNext()){ String i=iter1.next(); System.out.println(i+"****"+map1.get(i)); }
遍历Map的第二种方式 :.values()
Collection<String> value=map1.values(); Iterator<String> iter2=value.iterator(); while(iter2.hasNext()){ String j=iter2.next(); System.out.println(j); }
遍历Map的第三种方式 .entrySet()
Entry 是java提供的一种特殊的数据类型,其实就是一个键值对;key和value分别使用getKey和getValue取到;
Set<Entry<String,String>> set3=map1.entrySet(); Iterator <Entry<String,String>> iter3=set3.iterator(); while(iter3.hasNext()){ Entry<String,String> k=iter3.next(); System.out.println(k.getKey()+" "+k.getValue()); }