认识集合
- 集合都在JDK中java.util包下;
- 集合分为两大类
- 单个方式存储元素(超级父接口:java.util.Collection;)
- 键值对的方式存储元素(超级父接口:java.util.Map;)
- 集合是一种存放对引用(内存地址)的容器,集合中不能直接存储对象与基本类型
- 每一种集合对应着不同的数据结构,不同给的数据结构,采用的存储方式不同。
- 集合常用接口结构图
1、创建集合对象
//Collection c=new Collection(); 接口不能实例化
//多态,父类型引用子类型对象,可以实现子类型对象方法
Collection C = new ArrayList();
2、Collection 接口中常用方法
1.boolean add(Object o);
- 向集合中添加集合元素:默认
C.add(10_0000_0000);//自动装箱(java5的新特性// ),实际上是放了一个对象的内存地址点对于Integer x=new Integer(10_0000_0000);
C.add(new Object());
C.add(new student());
2.boolean remove(Object o);
- 删除集合中某一个元素
C.remove();
3.int size();
- 获取集合中元素的个数。
//size();获取集合中元素的个数。
System.out.println("集合里有"+ C.size()+"元素");
4.boolean contains(Object o);
-
检测集合是否包含指定元素。有则出true,无则出false。
-
底层是:引用equals方法,匹配元素。
boolean b=C.contains("李楠");
System.out.println(b);
5.void clear(Object o)
- 清空集合
C.clear();
6.boolean isEmpty(Object 0);
- 判断集合是否为空,true 没有元素,false有元素。
System.out.println("判断集合是否为空");
System.out.println(C.isEmpty());
7.Object[] toArray();
- 将集合转化为数组
System.out.println("toArray()将集合转换为数组");
//遍历出数组
for (Object a:C.toArray()){
System.out.println(a);
}
注意:collection接口中 remove、 contains方法都会调用底层equals方法。
-
无论重不重写equals方法,contains方法都会调用equals,重写了就会调用重写方法,不重写调用Object中的equals方法
-
Object中的equals方法:public boolean equals(Object obj) {return (this == obj); }比较的是内存地址
3、迭代器(Iterator方法)
1.迭代器基本
- **作用:**迭代(遍历)集合
- 注意:
- 集合翻身改变时,重写迭代器。
- 在Map集合中不能使用,在所有的Collection以及子类中使用。
- 迭代出的数据只能使用Object接收。(类型还是储存时的类型)
- 特别注意、注意、注意:
- 当集合结构发生改变的时候(集合增删改),迭代器不会自动刷新,没有重写迭代器时,调用next方法,会报错。
- 报错:java.util.ConcurrentModificationException
- 当迭代器对象调用iterator中的remove方法时,会更新迭代器,不会报错。
- remove();迭代器iterator中的删除元素的方法。
- 当集合结构发生改变的时候(集合增删改),迭代器不会自动刷新,没有重写迭代器时,调用next方法,会报错。
public static void main(String[] args) {
//接口无法实例化,可以利用多态:父类引用子类型对象
Collection c= new ArrayList();//后面的集合无所谓,主要是看前面的Collection接口怎么遍历、迭代
//给集合c添加元素
c.add("string");
c.add("汉字");
c.add(1000_0000);
c.add(new Object());
//获取迭代器对象
Iterator iterator=c.iterator();
/*
Iterator接口中的两个方法:
1.Object next();返回迭代的下一个元素。
2.boolean hasNext();如果仍还有元素可以迭代,则返回true
*/
//调用迭代器对象中的方法
while (iterator.hasNext()){
//只能用Object类型接收
Object o=iterator.next();
System.out.println(o);
}
}
2.迭代器的通用性和HashSet的无序不可重复性()
public static void main(String[] args) {
//创建集合对象
Collection c= new HashSet();
//添加元素
c.add(100);
c.add(200);
c.add(300);
c.add(400);
c.add(500);
c.add(600);
c.add(700);
c.add(800);
c.add(900);
c.add(1000);
c.add(100);
//创建迭代器对象
Iterator it=c.iterator();
//通过迭代器中方法循环迭代集合
while(it.hasNext()){
System.out.println(it.next());
}/*
输出结果:400
800
100
500
900
200
600
1000
300
700
*/
}
-
迭代器基本里面,示例ArrayList()类的使用,这里也示例了在HashSet()中的使用,结果都是可以使用
-
只输出了一个100。说明元素重复时,没有成功录入
-
输出和存储时的顺序不一致
3、遍历集合的三种方法
-
迭代器、for循环、foreger循环(后两者只能在有下标的集合中使用)
-
**切记切记:**使用foreger增强型for循环时直接输出接收变量。
public static void main(String[] args) {
ArrayList<String> Str = new ArrayList<>();
Str.add("string01");
Str.add("string02");
Str.add("string03");
//迭代器遍历集合
System.out.println("迭代器遍历集合");
Iterator<String> it=Str.iterator();
while (it.hasNext()){
String s=it.next();
System.out.println(s);
}
//常规for循环遍历(只针对有下标的集合)
System.out.println("常规for循环遍历");
for (int i=0;i< Str.size();i++) {
System.out.println(Str.get(i));
}
//增强型foreach循环遍历循环(只针对有下标的集合)
System.out.println("增强型foreach循环遍历循环");
//因为是集合是String类型所以用string接收元素。
for (String s:Str){
System.out.println(s);
}
//创建integer类型集合
List<Integer> in=new ArrayList<>();
//添加元素
in.add(1);
in.add(2);
in.add(3);
//迭代器遍历集合
System.out.println("迭代器遍历integer集合");
Iterator<Integer> ite = in.iterator();
while (ite.hasNext()){
int i=ite.next();
System.out.println(i);
}
//常规for循环遍历integer集合
System.out.println("常规for循环遍历integer集合");
for (int i = 0; i < Str.size() ; i++) {
System.out.println(in.get(i));
}
//增强型for循环遍历integer集合
System.out.println("增强型for循环遍历integer集合");
for(Integer i:in){
//注意:增强型foreger循环输出时,直接输出(Integer)i
System.out.println(i);
}
4、LIst集合(接口)
1 、list集合示例
-
特点:
- 有序:集合元素有下标,从0开始,以1递增。
- 可重复:储存相同的元素(两个“1”)
-
List特有方法示例
public static void main(String[] args) {
//创建List集合对象
List list=new ArrayList();
//添加元素
//默认在末尾添加元素(一般使用)
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("aa");
//在指定位置插入元素:index(下标)element(元素)
//用的不多,对于ArrayList集合效率比较低。
System.out.println("在第一位插入:aa");
list.add(0,"aa");
//创建迭代器对象
Iterator it=list.iterator();
//迭代
while (it.hasNext()){
Object o=it.next();
System.out.print(o + "、");
}
System.out.println("根据下标获取第一位集合元素");
Object ind=list.get(0);
System.out.println(ind);
System.out.println();
System.out.println("根据下标修改元素第二位");
list.set(1,"A");
Object obj=list.get(1);
System.out.println(obj);
System.out.println();
System.out.println("输出返回列表中第一次出现的指定元素(aa)索引");
System.out.println(list.indexOf("aa"));
System.out.println();
System.out.println("输出返回列表中最后出现的指定元素(aa)索引");
System.out.println(list.lastIndexOf("aa"));
System.out.println();
System.out.println("移出集合中第一次出现的指定元素");
System.out.println("移出元素前:");
Iterator it2= list.iterator();
while (it2.hasNext()){
Object o=it2.next();
System.out.print(o+"、");
}
//移除方法
list.remove("aa");
System.out.println();
System.out.println("移出元素后:");
Iterator it3= list.iterator();
while (it3.hasNext()){
Object ob=it3.next();
System.out.print(ob+"、");
}
}
- 输出结果:~~~
在第一位插入:aa
aa、a、b、c、d、e、aa、
根据下标获取第一位集合元素
aa
根据下标修改元素第二位
A
输出返回列表中第一次出现的指定元素(aa)索引
0
输出返回列表中最后出现的指定元素(aa)索引
6
移出集合中第一次出现的指定元素
移出元素前:
aa、A、b、c、d、e、aa、
移出元素后:
A、b、c、d、e、aa、
Process finished with exit code 0
2、ArrayList集合:
1、默认初始化容量为10。(底层先创建了,一个长度为0的数组,当添加第一个元素的时候,初始化容量为10)
- ArrayList集合是非线程安全的,不是线程安全的集合。
2、ArrayList集合底层是一个Object[]数组。
3、构造方法:
-
new ArrayList();
-
new ArrayList(20);
4、ArrayList集 合的扩容: 扩容到原容量的1.5倍。
- ArrayLIst集合怎么优化?
- ArrayList集合底层是数组,数组扩容效率比较低,减少扩容。
- 建议在使用ArrayList的时候预估计元素的个数,给定一个初始化容量。
5、数组的优缺点:
-
优点:检索效率比较高。
- 每个元素占用的空间相同,内存地址是连续的,知道元素的内存地址,通过数学表达式计算出元素的内存地址,所以检索效率最高。
-
缺点:
1.随机增删元素的效率比较低,向数组末尾添加元素的效率还是很高的。
2.数组无法存储大数据量。(很难找到巨大的连续内存空间。)
使ArrayList集合线程安全的方法
Collections.synchronizedList(集合对象);
3、linkedList集合(链表结构)
- 没有初始化容量。
3.1、单向链表
- (头节点:header、尾节点:last)
- 基本单元是节点Node。
- 节点中有两个属性:存储的数据,下一节点的内存地址。
- 优点:随机增删元素效率较高(因为严肃不涉及到大量元素的位移)
- 缺点:查询效率较低,每一次查找某个元素的时候都需要从头节点开始往下遍历。
3.2、双向链表
- 多了一个前节点内存地址
3.3总结:
- LinedList集合是双向链表。
- 对于链表数据结构来说,随机增删效率较高,检索效率较低。
- 链表中的元素在空间存储上,内存地址不连续。
4、Vector
-
默认容量10;当元素超过10,扩容后是原容量的2倍。
-
Vector中所有的方法都是线程同步的,都带有synchronized关键字,线程安全,但是效率较低。使用较少。
5、泛型
- 泛型这种预发机制,只在程序编译的阶段起作用,只是给编译器参考。(运行阶段泛型没用)
-
优点:
1、集合中元素类型更加统一
2、从集合中取出泛型指定的类型,不用大量的“向下转型”! -
缺点:
1、使用泛型了之后,集合只能存放(集合允许存储的)泛型指定的元素类型,导致集合中存储的元素缺乏多样性!
-
注:大多数业务中,集合中元素的类型还是同一的,多以这种泛型特性还是被大家所认可的。
1. 不使用泛型迭代集合示例
public class Generic01 {
public static void main(String[] args) {
//创建集合对象
List list= new ArrayList();
//创建元素
father f=new father();
boy1 b1=new boy1();
boy2 b2=new boy2();
//添加元素至集合
list.add(f);
list.add(b1);
list.add(b2);
//迭代集合
Iterator it=list.iterator();
while (it.hasNext()){
//强制转换
father obj=(father) it.next();
obj.f1();
}
}
}
//准备对象类型
class father{
public void f1(){
System.out.println("父类");
}
}
class boy1 extends father{
public void b1(){
System.out.println("子类1");
}
}
class boy2 extends father{
public void b2(){
System.out.println("子类2");
}
}
- 输出结果:
父类
父类
父类
//结果证明,并没有输出对象方法,只是输出内存地址
2、使用泛型迭代集合
public static void main(String[] args) {
//创建集合对象
//<father>指定了集合对象能存储的元素只能father类型。
List<father> list=new ArrayList<father>();
//创建元素
father f=new father();
boy1 b1=new boy1();
boy2 b2=new boy2();
//添加元素至集合
//使用泛型的短板是:
list.add(b1);
list.add(b2);
//迭代集合
//<father>表示迭代器是father类型。
Iterator<father> it=list.iterator();
while (it.hasNext()){
//不用强制类型转换,直接就能调用。
father fa=it.next();
fa.f1();
//调用子类特有方法
father a=it.next();
if(a instanceof boy1){
boy1 bb1=(boy1)a;
bb1.b1();
}
if(a instanceof boy2){
boy2 bb2=(boy2)a;
bb2.b2();
}
}
}
}
//准备对象类型
class father{
public void f1(){
System.out.println("父类");
}
}
class boy1 extends father{
public void b1(){
System.out.println("子类1");
}
}
class boy2 extends father{
public void b2(){
System.out.println("子类2");
}
}
- 输出结果:
父类
父类
父类
//结果一致。
3、钻石表达式
-
//List<father> mylist =new ArrayList<可以省略不写>(); List<father> mylist=new ArrayList<>();
public class Generic03 {
/*
泛型
自动类型推断机制又称(钻石表达式)
*/
public static void main(String[] args) {
//创建类型对象
//ArrayList<这里会自动推断是什么类型>,前前提是JDK8之后才允许的。
List<father> mylist=new ArrayList<>();
//添加集合元素
mylist.add(new father());
mylist.add(new boy1());
mylist.add(new boy2());
//遍历集合
Iterator<father> it=mylist.iterator();
while (it.hasNext()){
father f=it.next();
f.f1();
}
}
}
4、自定义泛型
-
自定义泛型的时候,<>中是一个表示符(可以随便写)。
-
java中源代码中经常出现的是:
<E>和<T>
-
E是Element单词首字母。
-
T是Type单词首字母。
-
public class n_Generic04<标识符随便写>{
//创建方法
public void doSome(标识符随便写 o){
System.out.println("已执行DoSOEM方法");
System.out.println(o);
}
public static void main(String[] args) {
//new对象的时候指定了泛型是:string类型
n_Generic04<String> ng = new n_Generic04();
//类型不匹配
ng.doSome("ng——01标识符随便写");
}
}
6、Set集合(接口)
- 1、无序性:存取顺序不一致(没有下标,可以使用foreger循环遍历,foreger底层是用iterator迭代器实现的)
- 2、元素不可重复:不可以存储重复元素
1.HashSet集合特点
- 1、无序性:存取顺序不一致
- 2、元素不可重复:不可以存储重复元素
- 3、放到HashSet集合中的元素实际上是放到了hashMap集合的key部分了。
public class HashSetDome01 {
public static void main(String[] args) {
HashSet<String> strings = new HashSet<>();
strings.add("String1");
strings.add("String2");
strings.add("String3");
strings.add("String1");
Iterator<String> it = strings.iterator();
while (it.hasNext()){
String s=it.next();
System.out.println(s);
}
for (String s:strings){
System.out.println(s);
}
}
}
/*输出结果:String3
String2
String1
*/
2.TreeSet集合
特点:
-
无序不可重复
-
自动排序由小到大、由前到后。
public class TreeSetDome01 { /* treeSet集合存储元素特点: 1、 */ public static void main(String[] args) { TreeSet<Integer> integer = new TreeSet<>(); integer.add(5); integer.add(1); integer.add(2); integer.add(3); integer.add(4); for (int i:integer){ System.out.println(i); } } } /* 输出结果:1 2 3 4 5 */
7、Map集合(接口)
-
特点:无序不重复
- 当key值重复时,value会覆盖
-
1.Map和collection没有继承关系。
-
2.Map集合以key和value的方式存储数据:键值对
- key和value都是引用数据类型。
- key和value都是存储对象的内存地址。
- key起主导的地位,value是key的附属品。
1.Map集合中常用的方法
public static void main(String[] args) {
//创建map集合
Map<Integer, String> hm = new HashMap<>();
//向map集合中添加键值对
hm.put(1,"元素1");
hm.put(2,"元素2");
hm.put(3,"元素3");
hm.put(4,"元素4");
hm.put(5,"元素5");
hm.put(6,"元素6");
//通过key获取value
hm.get(2);
System.out.println(hm.get(2));
//contains方法底层都是调用的equals方法
//判断集合中是否包含指定key
System.out.println(hm.containsKey(1));
//判断集合中是否包含指定元素value
System.out.println(hm.containsValue("元素1"));
//判断集合中的元素是否为0
System.out.println(hm.isEmpty());
//获取Map集合中所有的key
System.out.println(hm.keySet());
//获取Map集合中所有的value
System.out.println(hm.values());
//通过key删除键值对
hm.remove(1);
//获取map集合中所有键值对的数量
System.out.println(hm.size());
//将map集合转换成set集合
System.out.println(hm.entrySet());
//清空map集合
hm.clear();
System.out.println(hm.size());
}
}
2.遍历Map集合示例
public static void main(String[] args) {
//创建Map集合
Map<Integer, String> hm = new HashMap<>();
//添加键值对
hm.put(1,"String1");
hm.put(2,"String2");
hm.put(3,"String3");
hm.put(4,"String4");
hm.put(5,"String5");
//1、迭代器Map遍历
/*
1、首先拿到键值对的key,用set集合接收
2、遍历集合set集合
3、通过values方法获得key对应的value
*/
Set<Integer> s=hm.keySet();
Iterator<Integer> it=s.iterator();
while (it.hasNext()){
Integer i=it.next();
System.out.println(i+"="+hm.get(i));
}
/*
通过foreger增强型for循环遍历
1、创建接收key的集合
2、遍历集合set集合
3、通过values方法获得key对应的value
*/
Set<Integer> inte =hm.keySet();
for(Integer in:inte){
System.out.println(in+"="+hm.get(in));
}
}
3.HashMap(非线程安全)
-
(HashMap是对哈希表的一个应用实现)
-
HashMap的默认初始容量是16,默认加载因子是0.75.
-
加载因子:当HashMap集合底层数组的容量达到75%的时候,数组开始扩容。
-
哈希表是一个数组和单向链表的结合体。
-
数组:在查询方面效率很高,随机增删方面效率很低。
-
单向链表:在随机增删方面较高,查询方面很低。
-
而哈希表将以上的两种数据结构融合在一起,充分发挥他们各自的优点。(并没有原数据结构高效的地方,高效)
-
-
**重点:**HashMap集合初始化容量为了达到效率均匀,提高集合存取率必须是2的倍数。
-
当集合中的单向链表长度超过8的时候,单向链表这种结构会自动转换成红黑树数据结构。当红黑树上的节点小于6时,会重新把红黑树转换为单向链表这种结构。这种方式也是为了提高检索效率,二叉树的检索会再次缩小扫描范围,提高效率。
3.1、哈希表中的底层源码
public class HashMap{
//HashMap底层实际上就是一个数组(一维数组)
Node<K,V>[] table;
//静态的内部类HashMap
static class Node<K,V>{
final int hash;//哈希值:是key的HashCode()方法的执行结果。hash值通过哈希函数(算法)可以转换成数组的下标。
final K key;//存储到Map集合中的key值。
V value;//存储到Map集合中的value值。
Node<K,V>next; //下个节点的内存地址
}
3.2、添加键值对层原理(HashMap.put(value))
- 调用key的hashCode方法,获取哈希值。
- 哈希值通过哈希算法、函数,将hash值转换重数组下标。
- 如果下标没有没有任何元素,则把Node存储在此位置。
- 如果下标有对应的单向链表,此时就会用新节点的key值对比节点中的key值。
- 如果所有的equals方法都返回folse,则会吧新节点添加到单向链表结尾,如果equals方法返回true,则会覆盖对应节点的value。
3.3、获取键值对元素原理(HashMap.get(key))
- 调用key的hashCode方法,获取hash值。
- hash值通过哈希函数,计算出数组下标。
- 通过下标快速定位到数组的某个位置上。
- 如果此位置为空,则返回null。
- 如果此位置存在单向链表,那么获取节点的key值,和节点中的key值,进行equales方法比对。
- 如果equales方法返回false,那么get方法返回null、如果equales方法返回true,那么链表中与获取键值对对应的value,就是我们要找的value,get方法返回这个value。
3.4、特别注意:
- HashMap集合在添加、查询的时候,先后调用hashCode、equlae两个方法,那么这两个方法都需要重写。
- HashMap在使用不当,散列分布不均的时候,无法发挥性能,
- 假设有一百个元素,分布在由10个节点组成的10条链表上这就最均匀的,最好的(反之,则分散列布不均)。
- 哈希表:
- 如果两个键值对(元素)hash相等,那么这两个键值对一定会在一条单向链表上
- 如果不同,也有可能会在一条单向链表上。两个hash值有可能因为哈希算法之行结束之后转换的数组下标一样(哈希碰撞)。
- 哈希表扩容:原长度的2倍。
- HashMap集合中key值可以为Null。(只能有一个,不能违反hashMap的不可重复性)
4.hashCode与equals方法
-
Map集合在存取时,先调用hashCode方法在调用equales方法,
- 什么时候不需要调用equales方法:存取时,调用hashCode方法,获取哈希值,在通过哈希函数(算法)获取书序下标,当下标为null时不需要调用equales方法。
-
注意:
- 1、如果equales方法重写,hashCode方法必须重写。
- 2、如果equales方法返回true,那么hashCode方法必须返回true。
-
结论:放在HashMap集合key部分,以及放在HashMSte集合中的元素都需要重写hashCode与equales方法。
5.HashTable集合
-
HashTbable集合的
- 初始容量是1。
- 扩容是,原容量的2倍+1。
- key值与value值不允许为Null。
-
HashTable集合是线程安全的,其中所有的方法都带有synchronized关键字,效率较低,线程安全有别的办法,现在使用较少。
1.(子类)Properties集合
- 注意:
- properties集合的key与value值只能存储String类型的数据。
- 通过key值获取value值的方法不同。
public static void main(String[] args) {
//创建一个properties集合对象
Properties ppt = new Properties();
//添加元素(调用的还是HashTable的put方法)
ppt.put("key1","value1");
ppt.put("key2","value2");
ppt.put("key3","value3");
//通过key值获取对应的value值(获取的调用自己的properties方法)
System.out.println(ppt.getProperty("key1"));
}
- 输出结果:value1
6. TreeMap集合(Comparable接口)
-
特点:
- TreeSte集合中的元素:无序不可重复。
- TreeSte集合中的元素:可以自动通过元素的自然大小排序。
-
注意:
-
treeSet集合底层是把元素存储在了TreeMap集合中给的key部分中。
-
TreeMap集合底层实际上是一个二叉树结构。
-
-
TreeSet集合自定义类型示例
public class TreeSetText03 { public static void main(String[] args) { //创建集合对象 TreeSet<Vip> svip = new TreeSet<>(); //创建、添加元素 Vip v1 = new Vip("张三",12); Vip v2 = new Vip("李大爷",56); Vip v3 = new Vip("关孙子",20); Vip v4 = new Vip("丑龙",12); svip.add(v1); svip.add(v2); svip.add(v3); svip.add(v4); for (Vip v:svip){ System.out.println(v); } } } /* 输出结果: Vip{name='丑龙', age=12} Vip{name='张三', age=12} Vip{name='关孙子', age=20} Vip{name='李大爷', age=56} */
-
对象类型(注意三点)
-
实现Comparable接口。
-
重写比较(排序)规则compareTo方法。
-
重写ToString方法。
-
-
**特别重要:**compareTo方法的返回值
- 等于0:value值会覆盖。
- 小于0:会在右子树上找。
- 大于0:会在左子树上找。
public class Vip implements Comparable<Vip>{ private String name; private int age; //传参构造方法 public Vip(String name, int age) { this.name = name; this.age = age; } //重写通String方法 @Override public String toString() { return "Vip{" + "name='" + name + '\'' + ", age=" + age + '}'; } //重写compareTo方法(排序规则) @Override public int compareTo(Vip o) { return this.age - o.age; }
-
-
嵌套排序示例:安照年龄排序相等年龄的人在按姓名排序。
- 与上不同的是,在compareTo方法中多调用了String的compareTo方法比较String类型的姓名。
public class Vip implements Comparable<Vip>{
private String name;
private int age;
public Vip(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Vip{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Vip o) {
if(this.age==o.age){
return this.name.compareTo(o.name);
}else {
return this.age - o.age;
}
}
}
7.二叉树
-
存储:遵循左小右大的存储原则,每次储存的时候都会和根比较,存放的过程就是排序的过程。
-
遍历:(根在前是前序、根在中是中序、根在后是后序)
- 前序遍历:根左右
- 中序遍历:左根右(遍历出来的值会自动按大小排序)
- 后序遍历:左右根
-
TreeSte、TreeMap集合和Iterator迭代器,采用的都是中序遍历:左根右。
-
大致结构图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fHUM2wqY-1596031592043)(C:\Users\000\AppData\Roaming\Typora\typora-user-images\image-20200729161759237.png)]
8.自定义比较器(Comparator)
1、建立Comparator比较器(两种方法)
- implements Comparator比较器类型并指定泛型
- 重写 Comparator自定义比较器中的Compare比较方法
class PeopleComparator implements Comparator<People> {
@Override
public int compare(People o1, People o2) {
return o1.age-o2.age;
}
}
2、匿名内部类建立
- 在新建集合的时候,直接以匿名内部类的方式插入Comparator比较器
- 并在内重写 Comparator自定义比较器中的Compare比较方法
TreeSet<People> peo = new TreeSet<>(
//在新建集合的时候传进一个Comparator比较器
new Comparator<People>() {
@Override
public int compare(People o1, People o2) {
return o1.age-o2.age;
}
});
- Comparator比较器的使用
- 在新建集合的时候传入使用
public class TreeMapComparator01 {
public static void main(String[] args) {
//创建集合
TreeSet<People> peo = new TreeSet<>(new comparator<People>());
//添加People类型元素
peo.add(new People(12));
peo.add(new People(11));
peo.add(new People(14));
peo.add(new People(10));
//遍历集合
for(People i:peo){
System.out.println(i);
}
}
}
//创建人类,有年龄属性
class People{
int age;
//有参构造器
public People(int age) {
this.age = age;
}
@Override
public String toString() {
return "People{" +
"age=" + age +
'}';
}
}
//创建Comparator比较器
class PeopleComparator implements Comparator<People> {
@Override
public int compare(People o1, People o2) {
return o1.age-o2.age;
}
}
- Comparator与Comparable比较器的区别
- Comparatble是接口,如果规则是一成不变的建议使用
- Comparator是自定义比较器,灵活一些,对于多、变的规则,建议使用。
8、Collections工具类
- 注意点:Collection是接口,而Collections是集合的工具类。
1.Sort方法:
- List集合的排序方法
2.synchronized*( * :集合类型)方法
-
转换成线程安全的
public class CollectionsTest01 { public static void main(String[] args) { //新建一个ArrayList集合 ArrayList<String> al = new ArrayList<>(); //添加元素 al.add("adf"); al.add("bdf"); al.add("cf"); al.add("adf"); //变成线程安全的 Collections.synchronizedList(al); //调用Collections中的方法排序 Collections.sort(al); //遍历集合 for(String s:al){ System.out.println(s); } System.out.println("=============================="); //新建一个自定义泛型list集合 ArrayList<guisun> gs = new ArrayList<>(); gs.add(new guisun("龟儿1")); gs.add(new guisun("龟儿2")); gs.add(new guisun("龟儿4")); gs.add(new guisun("龟儿1")); gs.add(new guisun("龟儿3")); //自定义类型排序时注意:对list集合中元素排序,需要保证list集合中的元素实现了比较器:Comparable接口、指定准确泛型。 Collections.sort(gs); for (guisun g:gs){ System.out.println(g); } System.out.println("=================测试Set集合============="); Set<String> set = new HashSet<>(); set.add("3"); set.add("9"); set.add("0"); set.add("7"); set.add("4"); //Collections中的sort方法只能对List集合排序。 //将set集合转换成list集合 List<String> setlist = new ArrayList(set); Collections.sort(setlist); for (String l:setlist){ System.out.println(l); } } }
//创建自定义元素类型
//注意指定泛型,(默认的不一定是你需要的)
class guisun implements Comparable{
private String name;
@Override
public String toString() {
return "guisun{" +
"name='" + name + '\'' +
'}';
}
public guisun(String name) {
this.name = name;
}
public guisun() {
}
@Override
public int compareTo(guisun o) {
return this.name.compareTo(o.name);
}
}