一.集合
集合:Java API所提供的一系列类,可以用于动态存放多个对象。
集合类全部支持泛型,是一种数据安全的用法。
LinkedList<String> list = new LinkedList<>();
集合与数组不同在于:
1.集合是大小可变的序列,数组一旦声明长度不可变
2.同一个集合可以存放多种数据类型,数组只能存放声明时指定的数据类型
3.集合只能存储引用数据类型,数组可以存储基本数据类型及引用数据类型
另外还有三个分支,均是为上述两大家族服务的。
Iterator(迭代器)家族。主要用于遍历Colleciton接口的及其子类而设计。
Comparator(比较器), 在集合中存储对象时候,用于对象之间的比较
Collections是工具类。注意该类名带个s,一般就表示工具类。里面提供了N多静态方法,来对Colleciton集合进行操作。
二.Collection接口
该接口下的所有子孙类均存储的是单一对象。 Add(s)
Collection接口-定义了存取对象的方法。有两个非常常用的子接口:
List接口:存放的元素有序且允许有重复的集合接口。
Set接口:存放的元素无序不包含重复的集合接口。
说明:
“有序”-元素存入的顺序与取出的顺序相同.
“无序”—元素存入的顺序与取出的顺序不相同
(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的,加入Set 的Object必须定义equals()方法 ,另外list支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。)
Collection接口中的常用方法
- int size(); 返回此collection中的元素数。
- boolean isEmpty(); 判断此collection中是否为空。
- boolean contains(Object obj); 判断此collection是否包含指定的元素。
- boolean contains(Collection c); 判断此collection是否包含指定collection中的所有元素。
- boolean add(Object element); 向此collection中添加元素。
- boolean addAll(Collection c); 将指定collection中的所有元素添加到此collection中
- boolean remove(Object element); 从此collection中移除指定的元素。
- boolean removeAll(Collection c); 移除此collection中那些也包含在指定collection中的所有元素。
- void clear(); 移除些collection中所有的元素。
- boolean retainAll(Collection c); 仅保留此collection中那些也包含在指定collection的元素。
- Iterator iterator(); 返回在此collection的元素上进行迭代的迭代器。
- Object[] toArray(); 把此collection转成数组。
1.List接口
(1)ArrayList
数据结构:一维数组
特点:有序、可重复,长度不固定,线程不安全,效率高。
优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。
缺点:因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。
应用场景:存储数据
public class Test01 {
public static void main(String[] args) {
//创建ArrayList对象
ArrayList list = new ArrayList();
//添加
list.add("古川伊织");
list.add("明日花");
list.add("谢刚");
list.add("麻生希");
list.add(18);//默认自动装箱:Integer.valueOf(18);
//获取元素
System.out.println("获取指定下标上的元素:" + list.get(0));
//获取个数
System.out.println("获取集合中元素的个数:" + list.size());
//查询、判断
System.out.println("查询该集合是否没有元素:" + list.isEmpty());
System.out.println("判断该集合是否有指定元素:" + list.contains("明日花"));
System.out.println("查询该元素在集合中的下标:" + list.indexOf("谢刚"));
//替换
list.set(3, "爱田奈奈");
//删除
list.remove(2);//以下标删除
list.remove("明日花");//以元素删除
//遍历1:for循环
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("---------------");
//遍历2:foreach
for (Object obj : list) {
System.out.println(obj);
}
System.out.println("---------------");
//遍历3:迭代器
Iterator it = list.iterator();
while(it.hasNext()){//判断是否有迭代的元素
Object next = it.next();//获取元素
System.out.println(next);
}
}
}
输出:
获取指定下标上的元素:古川伊织
获取集合中元素的个数:5
查询该集合是否没有元素:false
判断该集合是否有指定元素:true
查询该元素在集合中的下标:2
古川伊织
爱田奈奈
18
---------------
古川伊织
爱田奈奈
18
---------------
古川伊织
爱田奈奈
18
(2)LinkedList
数据结构:双向链表
特点:有序、可重复。
优点:LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景
缺点:因为LinkedList要移动指针,所以查询操作性能比较低。
适用场景分析:
当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。
应用场景:存储数据、栈模式(removeLast)、队列模式(removeFirst)
public class Test01 {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
//删除
list.remove(2);//以下标删除
list.remove("D");//以元素内容删除
//查询
System.out.println("查询该元素在集合中的下标:"+list.indexOf("A"));
System.out.println("查询集合是否为空:"+list.isEmpty());
System.out.println("查询是否有该元素:"+list.contains("A"));
//替换
list.set(1, "b");
//遍历1:迭代器遍历
Iterator<String> it = list.iterator();
while(it.hasNext()) {//判断是否有迭代的元素
String next = it.next();//获取元素
System.out.println(next);
}
System.out.println("集合中元素的个数为:"+list.size());
//遍历2:for循环
for(int i=0;i<list.size();i++) {
System.out.println(list.get(i));
}
//遍历3:foreach(底层由迭代器实现)
for(String str:list) {
System.out.println(str);
}
}
}
输出:
查询该元素在集合中的下标:0
查询集合是否为空:false
查询是否有该元素:true
A
b
集合中元素的个数为:2
A
b
A
b
public class Test03 { public static void main(String[] args) { //栈模式:先进后出 LinkedList<String> list =new LinkedList<>(); list.add("元素1"); list.add("元素2"); list.add("元素3"); list.add("元素4"); //遍历 while(!list.isEmpty()) { String string = list.removeLast();//删除并返回最后一个元素 System.out.println(string); } System.out.println(list.size()); } } 输出: 元素4 元素3 元素2 元素1 0
import java.util.LinkedList; public class Test04 { public static void main(String[] args) { //队列模式:先进先出 LinkedList<String> list =new LinkedList<>(); list.add("元素1"); list.add("元素2"); list.add("元素3"); list.add("元素4"); //遍历 while(!list.isEmpty()) { String string = list.removeFirst();//删除并返回第一个元素 System.out.println(string); } System.out.println(list.size()); } } 输出: 元素1 元素2 元素3 元素4 0
ArrayList 与 LinkedList的区别:
1.ArrayList与LinkedList实现了List接口,所以基本使用完全相同
2.LinkedList有队列模式和栈模式的方法,分别是:removeFrist、removeLast
3.效率问题:
添加元素:ArrayList(不扩容的情况下快)
删除元素:LinkedList快
插入元素:LinkedList快
修改元素:ArrayList快
查询元素:ArrayList快
经验:在工作中,这两个集合,ArrayList会用的多一点,因为增删查改的功能中查询的功能最常用,如果使用队列模式或者栈模式就是用LinkedList
(3)Vector
数据结构:一维数组
特点:有序可重复,线程安全
Vector类中的方法很多有synchronized进行修饰,是多线程安全的,线程安全就是说多线程访问同一代码,不会产生不确定的结果。而ArrayList不是,这个可以从源码中看出,,这样就导致了Vector在效率上无法与ArrayList相比;
两个都是采用的线性连续空间存储元素,但是当空间不足的时候,两个类的增加方式是不同。
Vector可以设置增长因子,而ArrayList不可以。
Vector是一种老的动态数组,是线程同步的,效率很低,一般不赞成使用。
适用场景分析:
Vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用ArrayList效率比较高。如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector有一定的优势。
应用场景:存储数据、线程安全
public class Test01 {
public static void main(String[] args) {
Vector<String> vector = new Vector<>();
vector.add("元素1");
vector.add("元素2");
vector.add("元素3");
vector.add("元素4");
vector.remove(2);
Iterator<String> it = vector.iterator();
while(it.hasNext()) {
String next = it.next();
System.out.println(next);
}
}
}
输出:
元素1
元素2
元素4
public class Test02 {
public static void main(String[] args) {
//Vector较老名称的方法
Vector<String> vector = new Vector<>();
vector.addElement("元素1");
vector.addElement("元素2");
vector.addElement("元素3");
vector.addElement("元素4");
vector.removeElement("元素2");//以内容删除
vector.removeElementAt(1);//以下标删除
vector.setElementAt("元素5", 0);//替换
Enumeration<String> elements = vector.elements();
while(elements.hasMoreElements()) {
String nextElement = elements.nextElement();
System.out.println(nextElement);
}
}
}
输出:
元素5
元素4
(4)Stock
数据结构:一维数组
特点:有序可重复,是Vector的子类
应用场景:存储数据、栈模式(push-放入,pop-拿出)
public class Test01 {
public static void main(String[] args) {
//Stack为栈模式
Stack<String> stack = new Stack<>();
//把元素压如栈顶
stack.push("元素1");
stack.push("元素2");
stack.push("元素3");
stack.push("元素4");
//遍历
while(!stack.isEmpty()) {
String pop = stack.pop();
System.out.println(pop);
}
}
}
2.set接口
set和list对比
- Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
- List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。
set和map区别
- List是对象集合,允许对象重复。
- Map是键值对的集合,不允许key重复。
(1)HashSet
数据结构:hash数组
应用场景:去重复(单个值存储)
public class Test01 {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
//添加
set.add("元素1");
set.add("元素2");
set.add("元素3");
set.add("元素4");
//以元素删除
set.remove("元素2");
//获取个数
System.out.println("元素个数为:"+set.size());
//查询、判断
System.out.println("查询该集合是否没有元素"+set.isEmpty());
System.out.println("判断该集合是否有指定元素"+set.contains("元素1"));
System.out.println("----------------------------------------");
//遍历1:foreach
for(String str:set) {
System.out.println(str);
}
System.out.println("----------------------------------------");
//遍历2:Iterator遍
Iterator<String> it = set.iterator();
while(it.hasNext()) {
String next = it.next();
System.out.println(next);
}
}
}
输出:
元素个数为:3
查询该集合是否没有元素false
判断该集合是否有指定元素true
----------------------------------------
元素1
元素3
元素4
----------------------------------------
元素1
元素3
元素4
import java.util.HashSet;
import java.util.Iterator;
public class Test02 {
public static void main(String[] args) {
//证明HashSet无序且不可重复
HashSet<Integer> set = new HashSet<>();
//添加
set.add(11);
set.add(22);
set.add(33);
set.add(33);
set.add(44);
//遍历
Iterator<Integer> it = set.iterator();
while(it.hasNext()) {
Integer next = it.next();
System.out.println(next);
}
}
}
输出:
33
22
11
44
(2)TreeSet
数据结构:二叉树
String类型 字典排序
Integer类型 自然排序
public class Test01 {
public static void main(String[] args) {
//treeset基本使用
TreeSet<String> set = new TreeSet<>();
//添加
set.add("a");
set.add("b");
set.add("c");
set.add("d");
//查询、判断
System.out.println("查询集合中是否有该元素"+set.contains("a"));
System.out.println("查询集合是否为空"+set.isEmpty());
System.out.println("查询集合中元素个数"+set.size());
//删除
set.remove("a");
//遍历1:foreach
for(String string : set) {
System.out.println(string);
}
System.out.println("------------");
//遍历2:迭代器
Iterator<String> it = set.iterator();
while (it.hasNext()) {
String string = (String) it.next();
System.out.println(string);
}
}
}
输出:
查询集合中是否有该元素true
查询集合是否为空false
查询集合中元素个数4
b
c
d
------------
b
c
d
3.Map接口
该接口下的所有子孙均存储的是key-value(键值对)形式的数据。Put(key,value)
Map没有迭代器,不能直接遍历数据。
(1)HashMap
数据结构:hash数组
应用场景:Key去重复(键值对存储)
HashMap 的工作原理
- Java中的HashMap是以键值对(key-value)的形式存储元素的。HashMap需要一个hash函数,它使用hashCode()和equals()方法来向集合/从集合添加和检索元素。
- 当调用put()方法的时候,HashMap会计算key的hash值,然后把键值对存储在集合中合适的索引上。
- 如果key已经存在了,value会被更新成新值。HashMap的一些重要的特性是它的容量(capacity),负载因子(load factor)和扩容极限(threshold resizing)。
- HashMap是基于哈希表的Map接口的非同步实现,提供所有可选的映射操作,并允许使用null值和null键,不保证映射的顺序;HashMap是一个“链表散列”的数据结构,即数组和链表的结合体;它的底层就是一个数组结构,数组中的每一项又是一个链表,每当新建一个HashMap时,就会初始化一个数组;
HashSet 和 HashMap 区别
- set是线性结构,set中的值不能重复,hashset是set的hash实现,hashset中值不能重复是用hashmap的key来实现的。
- map是键值对映射,可以空键空值。HashMap是Map接口的hash实现,key的唯一性是通过key值hash值的唯一来确定,value值是则是链表结构。
- 他们的共同点都是hash算法实现的唯一性,他们都不能持有基本类型,只能持有对象
HashMap 和 Hashtable 的区别
- 1.hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。
- 2.hashTable同步的,而HashMap是非同步的,效率上比hashTable要高。
- 3.hashMap允许空键值,而hashTable不允许。
注意:
TreeMap:非线程安全基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态。
Treemap:适用于按自然顺序或自定义顺序遍历键(key)。
遍历1:keySet():将map中的所有key获取出放在Set集合中,遍历set集合获取所有的key,就可以找到对应的value
遍历2:entrySet():将map中的所有映射关系获取出放在Set集合中,遍历set集合
public class Test01 {
public static void main(String[] args) {
//HashMap基本使用
HashMap<String, Integer> map = new HashMap<>();
//添加
map.put("元素1", 1);
map.put("元素2", 2);
map.put("元素3", 3);
map.put("元素4", 4);
//获取
System.out.println("获取value:"+map.get("元素1"));
//获取个数
System.out.println("查询集合中映射关系的个数:"+map.size());
//查询、判断
System.out.println("查询集合是否没有映射关系:"+map.isEmpty());
System.out.println("查询是否有指定key:"+map.containsKey("元素2"));
System.out.println("查询是否有指定value:"+map.containsValue(3));
//通过key删除映射关系
map.remove("元素1");
//遍历1:keySet():将map中的所有key获取出放在Set集合中,遍历set集合获取所有的key,就可以找到对应的value
Set<String> keySet = map.keySet();
for(String key:keySet) {
Integer value = map.get(key);
System.out.println(key+"---------"+value);
}
System.out.println("---------------------------------------");
//遍历2:entrySet():将map中的所有映射关系获取出放在Set集合中,遍历set集合
Set<Entry<String, Integer>> entrySet = map.entrySet();
for(Entry<String, Integer> entry:entrySet) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"---------"+value);
}
System.out.println("---------------------------------------");
}
}
输出:
获取value:1
查询集合中映射关系的个数:4
查询集合是否没有映射关系:false
查询是否有指定key:true
查询是否有指定value:true
元素2---------2
元素3---------3
元素4---------4
---------------------------------------
元素2---------2
元素3---------3
元素4---------4
---------------------------------------
public class Test02 {
public static void main(String[] args) {
//HashMap特点:key不能重复,value可以重复
HashMap<String, Integer> map = new HashMap<>();
//添加
map.put("元素1", 1);
map.put("元素2", 2);
map.put("元素3", 3);
map.put("元素4", 4);
//如果有相同key,就替换
map.put("元素1",2);
//value相同,不会替换
map.put("元素5", 2);
//输出
Set<Entry<String,Integer>> entrySet = map.entrySet();
for(Entry<String, Integer> entry:entrySet) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"-----------"+value);
}
}
}
输出:
元素1-----------2
元素2-----------2
元素3-----------3
元素4-----------4
元素5-----------2
public class Test03 {
public static void main(String[] args) {
//获取字符换中字符出现的次数
HashMap<Character, Integer> map = new HashMap<>();
String str = "abcbcabacbacba11231221";
char[] charArray = str.toCharArray();
for(char s:charArray) {
Integer value = map.get(s);
if(value==null)
map.put(s, 1);
else
map.put(s,value+1);
}
Set<Character> keySet = map.keySet();
for(Character key:keySet) {
Integer value = map.get(key);
System.out.println("字符" + key + "出现次数为:" + value);
}
}
}
输出:
字符a出现次数为:5
字符1出现次数为:4
字符b出现次数为:5
字符2出现次数为:3
字符c出现次数为:4
字符3出现次数为:1
(2)ConcurrentHashMap
应用场景:多线程下key去重(键值对存储),效率高
ConcurrentHashMap 的工作原理
- HashTable里使用的是synchronized关键字,这其实是对对象加锁,锁住的都是对象整体,当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。
- ConcurrentHashMap算是对上述问题的优化,其构造函数如下,默认传入的是16,0.75,16
- ConcurrentHashMap引入了分割(Segment),上面代码中的最后一行其实就可以理解为把一个大的Map拆分成N个小的HashTable,在put方法中,会根据hash(paramK.hashCode())来决定具体存放进哪个Segment,如果查看Segment的put操作,我们会发现内部使用的同步机制是基于lock操作的,这样就可以对Map的一部分(Segment)进行上锁,这样影响的只是将要放入同一个Segment的元素的put操作,保证同步的时候,锁住的不是整个Map(HashTable就是这么做的),相对于HashTable提高了多线程环境下的性能,因此HashTable已经被淘汰了。
HashMap 和 ConcurrentHashMap 的区别
- ConcurrentHashMap是线程安全的HashMap的实现。
- ConcurrentHashMap对整个数组进行了分割分段(Segment),然后在每一个分段上都用lock锁进行保护,相对于HashTable的syn关键字锁的粒度更精细了一些,并发性能更好,而HashMap没有锁机制,不是线程安全的。
- HashMap的键值对允许有null,但是ConCurrentHashMap都不允许。
public class Test05 {
public static void main(String[] args) {
//ConcurrentHashMap基本使用
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
//添加
map.put("谢刚", 22);
map.put("唐萌", 18);
map.put("伍科", 30);
map.put("李阳", 21);
//获取
System.out.println("通过指定key获取对应的value:" + map.get("唐萌"));
//获取个数
System.out.println("获取集合中映射关系的个数:" + map.size());
//查询、判断
System.out.println("查询该集合是否没有元素:" + map.isEmpty());
System.out.println("判断该集合是否有指定key元素:" + map.containsKey("李阳"));
System.out.println("判断该集合是否有指定value元素:" + map.containsValue(21));
//删除:通过key删除映射关系
map.remove("谢刚");
//遍历1:keySet():将map中的所有key获取出放在Set集合中,遍历set集合获取所有的key,就可以找到对应的value
Set<String> keySet = map.keySet();
for (String key : keySet) {
Integer value = map.get(key);
System.out.println(key + " -- " + value);
}
System.out.println("----------------");
//遍历2:entrySet():将map中的所有映射关系获取出放在Set集合中,遍历set集合
Set<Entry<String, Integer>> entrySet = map.entrySet();
for (Entry<String, Integer> entry : entrySet) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + " -- " + value);
}
}
}
输出:
通过指定key获取对应的value:18
获取集合中映射关系的个数:4
查询该集合是否没有元素:false
判断该集合是否有指定key元素:true
判断该集合是否有指定value元素:true
唐萌 -- 18
李阳 -- 21
伍科 -- 30
----------------
唐萌 -- 18
李阳 -- 21
伍科 -- 30
(3)Hashtable
应用场景:多线程下key去重(键值对存储),效率低
public class Test04 {
public static void main(String[] args) {
//Hashtable基本使用
Hashtable<String, Integer> map = new Hashtable<>();
//添加
map.put("谢刚", 22);
map.put("唐萌", 18);
map.put("伍科", 30);
map.put("李阳", 21);
//获取
System.out.println("通过指定key获取对应的value:" + map.get("唐萌"));
//获取个数
System.out.println("获取集合中映射关系的个数:" + map.size());
//查询、判断
System.out.println("查询该集合是否没有元素:" + map.isEmpty());
System.out.println("判断该集合是否有指定key元素:" + map.containsKey("李阳"));
System.out.println("判断该集合是否有指定value元素:" + map.containsValue(21));
//删除:通过key删除映射关系
map.remove("谢刚");
//遍历1:keySet():将map中的所有key获取出放在Set集合中,遍历set集合获取所有的key,就可以找到对应的value
Set<String> keySet = map.keySet();
for (String key : keySet) {
Integer value = map.get(key);
System.out.println(key + " -- " + value);
}
System.out.println("----------------");
//遍历2:entrySet():将map中的所有映射关系获取出放在Set集合中,遍历set集合
Set<Entry<String, Integer>> entrySet = map.entrySet();
for (Entry<String, Integer> entry : entrySet) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + " -- " + value);
}
}
}
输出:
通过指定key获取对应的value:18
获取集合中映射关系的个数:4
查询该集合是否没有元素:false
判断该集合是否有指定key元素:true
判断该集合是否有指定value元素:true
唐萌 -- 18
伍科 -- 30
李阳 -- 21
----------------
唐萌 -- 18
伍科 -- 30
李阳 -- 21
HashMap vs Hashtable vs ConcurrentHashMap
共同点:基本运用一致
区别1:
HashMap: 允许null的key和value
Hashtable: 不允许null的key和value
ConcurrentHashMap: 不允许null的key和value
区别2:
HashMap: 线程不安全
Hashtable: 线程安全(方法中加了synchronized同步锁)
ConcurrentHashMap: 线程安全(分段式加锁,把ReentrantLock锁上在了Segment对象中,效率更高)
(4)TreeMap
数据结构:二叉树
特点:key的位置自然排序
public class Test01 {
public static void main(String[] args) {
//TreeMap基本使用
TreeMap<String,Integer> map = new TreeMap<>();
//添加
map.put("a",1);
map.put("b",2);
map.put("c",3);
map.put("d",4);
//查询、判断
System.out.println("查询集合中是否有该元素"+map.containsKey("a"));
System.out.println("查询集合中是否有该元素"+map.containsValue(2));
System.out.println("查询集合是否为空"+map.isEmpty());
System.out.println("查询集合中元素个数"+map.size());
//删除
map.remove("a");
//遍历1:keySet
Set<String> keySet = map.keySet();
for(String key:keySet) {
Integer value = map.get(key);
System.out.println(key+"--------------"+value);
}
System.out.println("------------------");
//遍历2:entrySet
Set<Entry<String,Integer>> entrySet = map.entrySet();
for(Entry<String, Integer> entry:entrySet) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"--------------"+value);
}
}
}
输出:
查询集合中是否有该元素true
查询集合中是否有该元素true
查询集合是否为空false
查询集合中元素个数4
b--------------2
c--------------3
d--------------4
------------------
b--------------2
c--------------3
d--------------4
三、Comparator接口
Comparable接口 -- compareTo():类的对象要存入TreeSet中就必须实现此接口
Comparator接口 -- compare():在不能改动对象所属类的排序规则的情况下,在创建TreeSet时定义新的排序规则
优先级别:Comparator > Comparable
comparator 是javase中的接口,位于java.util包下,该接口抽象度极高,有必要掌握该接口的使用
大多数文章告诉大家comparator是用来排序,但我想说排序是comparator能实现的功能之一,他不仅限于排序
排序和分组的区别在于:
排序时,两个对象比较的结果有三种:大于,等于,小于。
分组时,两个对象比较的结果只有两种:等于(两个对象属于同一组),不等于(两个对象属于不同组)
学生类:实现了comparable接口,重写comparaTo
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
/**
* return 返回负数 小于此对象 0 等于此对象 正数 大于此对象
*/
public int compareTo(Student o) {
return this.age-o.age;
}
}
面向用户类:Comparator通过匿名内部类实现
public class Test02 {
public static void main(String[] args) {
//匿名内部类、Comparator
TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//姓名一样,年龄一样,返回1
if(o1.getName().equals(o2.getName()) && o1.getAge()==o2.getAge())
return 1;
//姓名长度不一样
if(o1.getName().length() !=o1.getName().length())
return o1.getName().length()-o2.getName().length();
//姓名长度一样,年龄不一样
if(o1.getName().length()==o2.getName().length() && o1.getAge()!=o2.getAge())
return o1.getAge()-o2.getAge();
return 1;
}
});
//添加
set.add(new Student("A同学哈", 11));
set.add(new Student("C同学哈1", 12));
set.add(new Student("B同学哈哈", 13));
set.add(new Student("B同学哈哈", 15));
set.add(new Student("D同学哈哈哈", 14));
//遍历,根据年龄排序
for (Student student : set) {
System.out.println(student);
}
}
}
输出
Student [name=A同学哈, age=11]
Student [name=C同学哈1, age=12]
Student [name=B同学哈哈, age=13]
Student [name=B同学哈哈, age=15]
Student [name=D同学哈哈哈, age=14]
四、Collections工具类
public class Test02 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
//批量添加
Collections.addAll(list, "bc","abcdef","cdb");
//依据此集合中数据类型的排序规则排序
// Collections.sort(list);
//自定义排序规则
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length()-o2.length();
}
});
输出:
bc
cdb
abcdef
//批量替换
Collections.fill(list, "同学");
for (String str : list) {
System.out.println(str);
}
}
}
输出:
同学
同学
同学
线程安全(Thread-safe)的集合对象:
- Vector 线程安全:
- HashTable 线程安全:
- ConcurrentHashMap 线程安全:
- StringBuffer 线程安全:
非线程安全的集合对象:
- ArrayList :
- LinkedList:
- HashMap:
- HashSet:
- TreeMap:
- TreeSet:
- StringBulider:
引用:
1.https://blog.csdn.net/qq_37017448/article/details/88871088