飞道的博客

【Java】集合基础——常用类基本使用

456人阅读  评论(0)

目录

接口 Collection

通用迭代器:接口 Iterator

List接口集合

List接口特有迭代器:接口 ListIterator

ListIterator迭代器的add()方法

List集合常用的具体子类

Set接口集合

哈希(散列)算法:简单演示图

双向链表演示图

Object.java的HashCode()方法代码段

HashSet存储元素过程

HashSet练习

二叉树 (简单介绍)

TreeSet练习(Comparable和Comparator接口)

增强For循环

通用For循环与增强For循环的区别:

Map接口集合,v>

Map集合遍历三种方式

Map集合常用子类

HashMap练习

TreeMap练习

Comparable接口和Comparator接口比较器

二叉树 (简单介绍)——方便看放这

Comparable(逆序排序)

Comparator(逆序排序)

Collections集合工具类

集合转数组

Arrays工具类(操作数组)

数组转集合注意


接口 Collection<E>

常用的接口和实现类

公有基类方法

通用迭代器:接口 Iterator<E>

用于遍历集合,返回的元素顺序根据实现类的不同而不同

remove():删除上一次调用next()返回的元素。

 

List<E>接口集合

List<E>接口特有迭代器:接口 ListIterator<E>

系列表迭代器,允许程序员按任一方向遍历列表(0 ~ n,length - 1 ~ 0)、最重要的是:这个迭代期间允许修改列表(添加或删除元素)。

需要注意的是:

ListIterator迭代器的add()方法

ListIterator迭代器的add()方法,不像ArrayList的add()方法一样是追加到末尾的。而ListIterator迭代器的add()方法会将数据插入到调用next()方法后的的后面,如果未调用过next()方法直接调用add()方法,会将元素插入到0索引的前面(之前0索引的元素变成了1索引的位置)。

通过next()指定位置后,add()方法能实现插入到指定位置

 

List<E>集合常用的具体子类

 

数据结构 优点 缺点
Vector

数组结构:通过删除或添加元素,会不断的new <T>[ size ];,

把旧的数组元素复制到新的数组中。

线程同步 增、删、查都慢
ArrayList

数组结构:通过删除或添加元素,会不断的new <T>[ size ];,

把旧的数组元素复制到新的数组中。

线程不同步,

查询快

增、删、慢
LinkedList

链表结构:在堆内存中的数据都是不规则的,通过连续添加元素会:

Object(0x0) <—— (0x0) Object (0x1) <—— (0x1) Object (0x2)  

<—— (0x2) Object (0x3) <—— (0x3) Object (0x4) ... ...n

也就是后一个添加的元素位置会记住前一个元素的地址

线程不同步,

增、删速度快

查询慢

 

Set<E>接口集合

和接口Collection的方法一样。正常情况下存储的元素是不重复的,而List是允许重复的。

常用具体子类

数据结构 优点
HashSet

哈希 ( 散列)结构。

使用注意:元素必须重写继承自超类Object的hashCode()和equals()方法。

重写hashCode():根据元素自身的特点计算哈希值。

重写equals():为了解决哈希值的冲突。

 

内部使用了HashMap

线程不同步,

查询更快

LinkedHashSet

链表 + 哈希 ( 散列)结构。

因为HashSet不保证元素添加时的顺序,

所以派生自HashSet类的LinkedHashSet就能保证元素添加时的顺序

在添加元素时此元素位置上记住上一次添加的元素的地址,所以就能保证迭代时的顺序。

线程不同步,

查询更快,

存入元素的有序

TreeSet

二叉树结构。

可对元素进行自定义排序方式。

基本数据类型会自然字典顺序排序(包括JDK某些实现了Comparable<T>接口)。

元素要具备比较性,需要实现Comparable<T>接口,重写int compareTo(Object o)方法,

返回数字有三个:

-1(只要是负数),代表小于。

1(只要是正数),代表大于。

0,相等就不存。

 

如果元素不实现Comparable<T>接口,可以构造一个Comparator<T>比较器

为了降低耦合性,可以构造一个带有Comparator<T>接口(比较器)的TreeSet,

而不是让元素实现Comparable<T>接口。

 

内部使用了TreeMap

线程不同步,

可以自定义排序方式。

 

 

 

 

哈希(散列)算法:简单演示图

为了解决哈希值冲突,延伸出来的位置:链表结构,更确切的说哈希表  =  数组 + 链表结构

java的String类字符串hashCode算法并不是像图上一样,仅演示,看图:

双向链表演示图

因为栈内存中的对象存储是不规则的,每次查询都要从头开始查询,所以链表查询慢,增删就特别快。

 

Object.java的HashCode()方法代码段


  
  1. public int hashCode() {
  2. int lockWord = shadow$_monitor_;
  3. final int lockWordStateMask = 0xC0000000; // Top 2 bits.
  4. final int lockWordStateHash = 0x80000000; // Top 2 bits are value 2 (kStateHash).
  5. final int lockWordHashMask = 0x0FFFFFFF; // Low 28 bits.
  6. if ((lockWord & lockWordStateMask) == lockWordStateHash) {
  7. return lockWord & lockWordHashMask;
  8. }
  9. //主要的方法,上面的代码段我不知道是干嘛用的,一般都只会执行下面的方法
  10. return System.identityHashCode( this); //将对象的内存16进制地址转换成整数作为HashCode值
  11. }
  12. public boolean equals(Object o) {
  13. return this == o; //只对比引用是否相同
  14. }
  15. //从这个方法知道,是对象的内存地址,通过hashCode值转换成的16进制地址
  16. //而hashCode值是内存16进制地址转换成
  17. public String toString() {
  18. return getClass().getName() + '@' + Integer.toHexString(hashCode());
  19. }

测试一般只执行System.identityHashCode(Object);方法是否成立:


  
  1. Object o = new Object();
  2. System.out. println( "地址 = " + o.toString());
  3. System.out. println( "hashCode() = " + o.hashCode());
  4. System.out. println( "toHex --> hashCode() = " + Integer.toHexString(o.hashCode()));
  5. System.out. println();
  6. System.out. println( "identityHashCode() = " + System.identityHashCode(o));
  7. System.out. println( "toHex --> identityHashCode() = " + Integer.toHexString(System.identityHashCode(o)));

输出:


  
  1. 地址 = java.lang.Object@ 15db9742
  2. hashCode() = 366712642
  3. toHex --> hashCode() = 15db9742
  4. identityHashCode() = 366712642
  5. toHex --> identityHashCode() = 15db9742

所以我们未重写默认的HashCode()方法值是通过对象的内存16进制地址转换为整数而成

 

HashSet存储元素过程

  1. 调用元素的hashCode()方法得到哈希值(调用底层函数,对象内存16进制地址转成的整数)
  2. 通过哈希值与容器大小%取余计算出位置
  3. 如果此位置上没有元素则添加。如果已有元素,则调用此位置上元素的equals(Object obj)进行比较:返回true则认为是相同的元素,不覆盖。返回false则认为是不同的元素,并对此位置上延伸一个新位置出来,进行添加。(正常情况下,

    返回false就要考虑减少元素的哈希算法冲突,这种情况很少发生)。

在使用Set集合前,必须重写原始类型Object的hashCode()和equals()方法。

当然,不重写也没关系,这样只能保证引用的不同而存储,引用相同而不覆盖。

什么时候可以重写?比如:为了保证对象内容数据的唯一而不重复。如下:

HashSet练习

需求:保证对学生对象数据的唯一性。相同数据的学生视为同一个人则不存。

思路:

  1. 利用以上HashCode值冲突原理。首先重写对象的hashCode()方法:逻辑为用内部数据计算出对象的哈希值(为了让相同数据的对象引起哈希冲突后进一步调用equals()方法比较数据是否相同)。
  2. 然后重写equals()方法:对比数据值是否相同,如果相同true则认为是同一个对象。
  3. 如果不同false则认为是不同的对象,此时就是真正的哈希值冲突了,这时候就要尽量保证哈希值算法对对象的唯一性,当然这种现象很少发生。

Student.java


  
  1. package com.bin.demo;
  2. public class Student {
  3. private String name;
  4. private int age;
  5. Student(String name, int age) {
  6. setName(name);
  7. setAge(age);
  8. }
  9. public String getName() {
  10. return name;
  11. }
  12. public void setName(String name) {
  13. this.name = name;
  14. }
  15. public int getAge() {
  16. return age;
  17. }
  18. public void setAge(int age) {
  19. this.age = age;
  20. }
  21. @Override
  22. public int hashCode() { //这里使用IDE自动生成的,当然也可以自定义
  23. final int prime = 31;
  24. int result = 1;
  25. result = prime * result + age;
  26. result = prime * result + ((name == null) ? 0 : name.hashCode());
  27. return result;
  28. }
  29. @Override
  30. public boolean equals(Object obj) { //hash值冲突相同,进一步地判断对象是否唯一
  31. if ( this == obj)
  32. return true;
  33. if (obj == null)
  34. return false;
  35. if (getClass() != obj.getClass())
  36. return false;
  37. Student other = (Student) obj; //这行代码到下面是判断,名字和年龄是否相同
  38. if (age != other.age)
  39. return false;
  40. if (name == null) {
  41. if (other.name != null)
  42. return false;
  43. } else if (!name.equals(other.name))
  44. return false;
  45. return true;
  46. }
  47. @Override
  48. public String toString() {
  49. return "Student [name=" + name + ", age=" + age + "]";
  50. }
  51. }

Main函数


  
  1. public class Main {
  2. public static void main(String[] args) {
  3. Set<Student> hs = new HashSet<Student>();
  4. hs. add( new Student( "超神", 17));
  5. hs. add( new Student( "剑圣", 16));
  6. hs. add( new Student( "铠甲", 18));
  7. hs. add( new Student( "斌哥", 20));
  8. hs. add( new Student( "神龙", 20));
  9. hs. add( new Student( "铠甲", 18));
  10. hs. add( new Student( "斌哥", 20));
  11. for (Student s : hs) {
  12. System. out.println(s.toString());
  13. }
  14. }
  15. }

输出:


  
  1. Student [name=铠甲, age=18]
  2. Student [name=神龙, age=20]
  3. Student [name=超神, age=17]
  4. Student [name=剑圣, age=16]
  5. Student [name=斌哥, age=20]

这就保证了不同对象的内部数据的唯一性。

 

二叉树 (简单介绍)

如图所见:我们在代码实现中,大的元素放右边,小的放左边,排序就是顺序排序(从小到大)。相反则_大的放左边,小的放右变,排序就是逆序排序(从大到小)。

 

TreeSet练习(Comparable<E>和Comparator<E>接口)

需求:对学生进行升序排序,依据年龄大小进行升序排序。如果年龄相等则对名字进行字典顺序排序,如果名字也相等则认为是相同一个人则不存。

Student.java 需要实现Comparable接口


  
  1. package com.bin.demo;
  2. public class Student implements Comparable<Student> {
  3. private String name;
  4. private int age;
  5. Student(String name, int age) {
  6. setName(name);
  7. setAge(age);
  8. }
  9. public String getName() {
  10. return name;
  11. }
  12. public void setName(String name) {
  13. this.name = name;
  14. }
  15. public int getAge() {
  16. return age;
  17. }
  18. public void setAge(int age) {
  19. this.age = age;
  20. }
  21. @Override
  22. public String toString() {
  23. return "Student [name=" + name + ", age=" + age + "]";
  24. }
  25. @Override
  26. public int compareTo(Student s) { //主要条件:age,次要条件:name
  27. // if (this.age > s.age) {
  28. // return 1;
  29. // } else if (this.age < s.age) {
  30. // return -1;
  31. // } else {
  32. // return this.name.compareTo(s.name);
  33. // }
  34. int isAge = this.age - s.age; //相减不是大于就是小于或等于
  35. return isAge == 0 ? this.name.compareTo(s.name) : isAge; // 如果年龄相等,按名字排序,使用的是字符串的字典顺序。如果名字相等还是返回0不存
  36. }
  37. }

main: 如果元素不实现Comparable接口,则使用Comparator接口比较器进行比较


  
  1. public class Main {
  2. public static void main(String[] args) {
  3. //同样可以使用比较器对:集合和元素降低耦合,这样可以构造Tree集合传入不同的排序方式
  4. Comparator<Student> cpt = new Comparator<Student>() {
  5. @ Override
  6. public int compare( Student news, Student s) {
  7. // if (news.getAge() > s.getAge()) {
  8. // return 1;
  9. // } else if (news.getAge() < s.getAge()) {
  10. // return -1;
  11. // } else {
  12. // return news.getName().compareTo(s.getName());
  13. // }
  14. int isAge = news.getAge() - s.getAge(); //相减不是大于就是小于或者等于
  15. return isAge == 0 ? news.getName().compareTo(s.getName()) : isAge; // 如果年龄相等则用名字进行升序排序,如果名字也相同则不存
  16. }
  17. };
  18. TreeSet<Student> ts = new TreeSet<Student>(cpt);
  19. ts. add( new Student( "超神", 17));
  20. ts. add( new Student( "剑圣", 16));
  21. ts. add( new Student( "铠甲", 18));
  22. ts. add( new Student( "斌哥", 20));
  23. ts. add( new Student( "神龙", 20));
  24. ts. add( new Student( "铠甲", 18));
  25. ts. add( new Student( "斌哥", 20));
  26. for (Student s : ts) {
  27. System. out.println(s);
  28. }
  29. }
  30. }

输出:


  
  1. Student [name=剑圣, age=16]
  2. Student [name=超神, age=17]
  3. Student [name=铠甲, age=18]
  4. Student [name=斌哥, age=20]
  5. Student [name=神龙, age=20]

使用Comparator比较器更为灵活,可以降低集合和元素之间的耦合。可以定义不同的比较器功能,对学生进行不同方式的排序。

 

增强For循环

增强For在JDK1.5开始出现,迭代功能就抽取出来了

Collection接口 就继承了 Iterable接口,

枚举接口Enumeration<E>迭代器,因为名称过长过时了(此接口只对Vector进行迭代)

JDK1.2后就被Iterator取代了枚举接口Enumeration<E>


  
  1. public class Main {
  2. public static void main(String[] args) {
  3. ArrayList<Integer> list = new ArrayList<Integer>();
  4. list.add( 1);
  5. list.add( 2);
  6. list.add( 3);
  7. list.add( 4);
  8. list.add( 5);
  9. Vector<Integer> v = new Vector<Integer>( list);
  10. //枚举方式迭代器,只有Vector拥有获取此迭代器的方法:已过时
  11. for (Enumeration<Integer> e = v.elements(); e.hasMoreElements();) {
  12. System.out.println(e.nextElement());
  13. }
  14. //通用for循环
  15. for (Iterator<Integer> li = list.listIterator(); li.hasNext();) {
  16. System.out.println(li.next());
  17. }
  18. //高级for循环
  19. for ( int i : list) {
  20. System.out.println(i);
  21. //list.add(-1); //发生并发修改异常:java.util.ConcurrentModificationException
  22. }
  23. }
  24. }

通用For循环与增强For循环的区别:

  • 增强For只能操作Collection接口的类型和数组,并且迭代期间不能操作元素。会报并发修改异常java.util.ConcurrentModificationException异常。
  • 通用For循环能操作索引,并且迭代期间可以对元素进行操作。
  • 所以增强For只为遍历,开发中减少代码。通用For还是比较强。

 

Map<K,V>接口集合

键值对的存储方式。保证键的唯一。

需要注意的方法:

  • put(K key, V value): 方法,将值与键进行关联,返回的是这个键与上一次关联的值,如果上一次并没有与该键关联的值就返回null。
  • remove(key): 删除该键的映射关系,并返回与该键关联的值,如果没有该键则返回null。
  • keySet(): 返回Set<K>集合的键。set 支持元素移除,通过 Iterator.remove 操作可从映射中移除相应的映射关系。它不支持 add 或 addAll 操作。
  • entrySet() : 返回 Set<Map.Entry<K,V>>集合,Map.Entry是Map接口里的内部的静态接口,此方法将每个键值对封装成了一个Map.Entry<K,V>,该接口有getKey()、getValue()、setValue(V v)、等方法。通过 Iterator.remove 操作可从映射中移除相应的映射关系。它不支持 add 或 addAll 操作。
  • values(): 返回Collection<V>集合,返回的都是值。collection 支持元素移除,通过 Iterator.remove 操作可从映射中移除相应的映射关系。它不支持 add 或 addAll 操作。

遍历时不能调用(除Iterator.remove()方法)外的添加和删除元素方法,否则会报 java.util.ConcurrentModificationException

Map集合遍历三种方式


  
  1. package com.bin.demo;
  2. import java.util.Collection;
  3. import java.util.HashMap;
  4. import java.util.Iterator;
  5. import java.util.Map;
  6. import java.util.Set;
  7. public class Main {
  8. public static void main( String[] args) {
  9. Map< String, Integer> m = new HashMap< String, Integer>();
  10. m.put( "A", 1);
  11. m.put( "B", 2);
  12. m.put( "C", 3);
  13. m.put( "D", 4);
  14. m.put( "E", 5);
  15. // keySet()
  16. Set< String> s = m.keySet();
  17. for (Iterator< String> i = s.iterator(); i.hasNext();) {
  18. String key = i.next();
  19. int value = m.get(key);
  20. System.out.println( "key = " + key + " ————> " + "value = " + value);
  21. } // 增强 for (String s : m.keySet())
  22. // entrySet()
  23. Set< Map.Entry< String, Integer>> me = m.entrySet();
  24. for (Iterator< Map.Entry< String, Integer>> i = me.iterator(); i.hasNext();) {
  25. Map.Entry< String, Integer> e = i.next();
  26. String key = e.getKey();
  27. int value = e.getValue();
  28. System.out.println( "key = " + key + " ————> " + "value = " + value);
  29. } // 增强 for (Map.Entry<String, Integer> e : m.entrySet())
  30. // values()
  31. Collection<Integer> c = m.values();
  32. for (Iterator<Integer> i = c.iterator(); i.hasNext();) {
  33. int value = i.next();
  34. System.out.println( "value = " + value);
  35. } // 增强 for (int value : m.values())
  36. }
  37. }

输出:


  
  1. key = A ————> value = 1
  2. key = B ————> value = 2
  3. key = C ————> value = 3
  4. key = D ————> value = 4
  5. key = E ————> value = 5
  6. key = A ————> value = 1
  7. key = B ————> value = 2
  8. key = C ————> value = 3
  9. key = D ————> value = 4
  10. key = E ————> value = 5
  11. value = 1
  12. value = 2
  13. value = 3
  14. value = 4
  15. value = 5

这里用的是HashMap,是不保证有序的

 

Map集合常用子类

数据结构 优点
HashTable 哈希表结构。

线程同步,

不允许Null键,

不允许Null值

HashMap 哈希表结构。

线程不同步,

允许Null键,

允许Null值。

LinkedHashMap 链表 + 哈希表结构。

线程不同步,

允许Null键,

允许Null值,

元素的插入是有序的。

TreeMap

二叉树结构。

元素需要具备比较功能。键需要实现Comparable<E>接口,

如果键不实现Comparable<E>接口,需要构造一个Comparator<E>比较器。

线程不同步,

可以对Map集合中的键进行自定义排序。

 

HashMap练习

需求:同样是对学生进行存储,键是学生对象(有名字和年龄),值是存学生当前所在的城市,学生名字和年龄一样则视为同一个人则不存。

Student.java 覆盖equals()和hashCode()方法。


  
  1. package com.bin.demo;
  2. public class Student {
  3. private String name;
  4. private int age;
  5. Student(String name, int age) {
  6. setName(name);
  7. setAge(age);
  8. }
  9. public String getName() {
  10. return name;
  11. }
  12. public void setName(String name) {
  13. this.name = name;
  14. }
  15. public int getAge() {
  16. return age;
  17. }
  18. public void setAge(int age) {
  19. this.age = age;
  20. }
  21. @Override
  22. public int hashCode() { //同样需要利用哈希冲突原理,然后用equals()方法进行数据的判断是否相同
  23. final int prime = 31;
  24. int result = 1;
  25. result = prime * result + age;
  26. result = prime * result + ((name == null) ? 0 : name.hashCode());
  27. return result;
  28. }
  29. @Override
  30. public boolean equals(Object obj) {
  31. if ( this == obj)
  32. return true;
  33. if (obj == null)
  34. return false;
  35. if (getClass() != obj.getClass())
  36. return false;
  37. Student other = (Student) obj;
  38. if (age != other.age)
  39. return false;
  40. if (name == null) {
  41. if (other.name != null)
  42. return false;
  43. } else if (!name.equals(other.name))
  44. return false;
  45. return true;
  46. }
  47. @Override
  48. public String toString() {
  49. return "Student [name=" + name + ", age=" + age + "]";
  50. }
  51. }

Main.java


  
  1. package com.bin.demo;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. public class Main {
  5. public static void main( String[] args) {
  6. Map<Student, String> m = new HashMap<Student, String>();
  7. m.put( new Student( "啊斌", 20), "广东");
  8. m.put( new Student( "雨烟", 19), "广西");
  9. m.put( new Student( "豪哥", 22), "江苏");
  10. m.put( new Student( "昌弟", 17), "广西");
  11. m.put( new Student( "贺弟", 18), "深圳");
  12. m.put( new Student( "益达", 23), "北京");
  13. m.put( new Student( "啊斌", 20), "广西"); //去了广西:新的值映射到键
  14. m.put( new Student( "雨烟", 19), "广东"); //去了广东:新的值映射到键
  15. for (Student s : m.keySet()) {
  16. String value = m.get(s);
  17. System.out.println( "key = " + s + " ————> 地址 = " + value);
  18. }
  19. }
  20. }

输出:


  
  1. key = Student [ name=益达, age= 23] ————> 地址 = 北京
  2. key = Student [ name=啊斌, age= 20] ————> 地址 = 广西
  3. key = Student [ name=贺弟, age= 18] ————> 地址 = 深圳
  4. key = Student [ name=雨烟, age= 19] ————> 地址 = 广东
  5. key = Student [ name=豪哥, age= 22] ————> 地址 = 江苏
  6. key = Student [ name=昌弟, age= 17] ————> 地址 = 广西

 

TreeMap练习

需求:同样是对学生进行存储。键是学生对象(有名字和年龄),值是存学生当前所在的城市,学生名字和年龄一样则视为同一个人则不存。升序排序:主要条件根据年龄进行排序,次要条件年龄相同后根据名字在编码表的顺序位置进行排序。

Student.java 实现Comparable接口


  
  1. package com.bin.demo;
  2. public class Student implements Comparable<Student> {
  3. private String name;
  4. private int age;
  5. Student(String name, int age) {
  6. setName(name);
  7. setAge(age);
  8. }
  9. public String getName() {
  10. return name;
  11. }
  12. public void setName(String name) {
  13. this.name = name;
  14. }
  15. public int getAge() {
  16. return age;
  17. }
  18. public void setAge(int age) {
  19. this.age = age;
  20. }
  21. @Override
  22. public String toString() {
  23. return "Student [name=" + name + ", age=" + age + "]";
  24. }
  25. @Override
  26. public int compareTo(Student s) {
  27. // if (this.age > s.age) {
  28. // return 1;
  29. // } else if (this.age < s.age) {
  30. // return -1;
  31. // } else {
  32. // return this.name.compareTo(s.name);
  33. // }
  34. int isAge = this.age - s.age; //相减不是大于就是小于或等于
  35. return isAge == 0 ? this.name.compareTo(s.name) : isAge; // 如果年龄相等则用名字进行升序排序,如果名字相同则不存
  36. }
  37. }

Main.java 如果元素不实现Comparable接口,可以使用Comparator接口比较器


  
  1. package com.bin.demo;
  2. import java.util.Comparator;
  3. import java.util.Map;
  4. import java.util.TreeMap;
  5. public class Main {
  6. public static void main(String[] args) {
  7. //同样可以使用比较器对:集合和元素降低耦合,这样可以构造Tree集合传入不同的排序方式
  8. Comparator<Student> cpt = new Comparator<Student>() {
  9. @Override
  10. public int compare(Student news, Student s) {
  11. // if (news.getAge() > s.getAge()) {
  12. // return 1;
  13. // } else if (news.getAge() < s.getAge()) {
  14. // return -1;
  15. // } else {
  16. // return news.getName().compareTo(s.getName());
  17. // }
  18. int isAge = news.getAge() - s.getAge(); //相减不是大于就是小于或者等于
  19. return isAge == 0 ? news.getName().compareTo(s.getName()) : isAge; // 如果年龄相等则用名字进行升序排序,如果名字也相同则不存
  20. }
  21. };
  22. Map<Student, String> m = new TreeMap<Student, String>(cpt);
  23. m.put( new Student( "啊斌", 20), "广东");
  24. m.put( new Student( "雨烟", 19), "广西");
  25. m.put( new Student( "豪哥", 22), "江苏");
  26. m.put( new Student( "昌弟", 17), "广西");
  27. m.put( new Student( "贺弟", 18), "深圳");
  28. m.put( new Student( "益达", 23), "北京");
  29. m.put( new Student( "啊斌", 20), "广西"); //去了广西:新的值映射到键
  30. m.put( new Student( "雨烟", 19), "广东"); //去了广东:新的值映射到键
  31. for (Student s : m.keySet()) {
  32. String value = m.get(s);
  33. System.out.println( "key = " + s + " ————> 地址 = " + value);
  34. }
  35. }
  36. }

输出:


  
  1. key = Student [ name=昌弟, age= 17] ————> 地址 = 广西
  2. key = Student [ name=贺弟, age= 18] ————> 地址 = 深圳
  3. key = Student [ name=雨烟, age= 19] ————> 地址 = 广东
  4. key = Student [ name=啊斌, age= 20] ————> 地址 = 广西
  5. key = Student [ name=豪哥, age= 22] ————> 地址 = 江苏
  6. key = Student [ name=益达, age= 23] ————> 地址 = 北京

 

Comparable接口和Comparator接口比较器

对于Tree集合来说。我们比较器返回的数值,顺序排序(从小到大)和逆序排序(从大到小)都是我们自己的逻辑实现的。

上面的二叉树练习都是顺序排序,所以下面是逆序排序学生的算方法

二叉树 (简单介绍)——方便看放这

如图所见:我们在代码实现中,大的元素放右边,小的放左边,排序就是顺序排序(从小到大)。相反则_大的放左边,小的放右变,排序就是逆序排序(从大到小)。

 

Comparable(逆序排序)


  
  1. @Override
  2. public int compareTo(Student s) {
  3. if ( this.age > s.age) {
  4. return -1; //新元素大于旧元素,就放左边
  5. } else if ( this.age < s.age) {
  6. return 1; //新元素小于旧元素,就放右边
  7. } else {
  8. return this.name.compareTo(s.name); //如果相等则不存
  9. }
  10. /*旧元素 减 新元素,
  11. * 返回的数据:新元素则会使用旧元素的对比(大、小)
  12. * 如果大于:则把新元素放到右边(此时新元素是小的)
  13. * 如果小于:则把新元素放到左边(此时新元素是大的)
  14. */
  15. // int isAge = s.age - this.age; //相减不是大于就是小于或等于
  16. // return isAge == 0 ? this.name.compareTo(s.name) : isAge; // 如果年龄相等则用名字进行升序排序,如果名字相同则不存
  17. }

Comparator(逆序排序)


  
  1. Comparator<Student> cpt = new Comparator<Student>() {
  2. @Override
  3. public int compare(Student news, Student s) {
  4. if (news.getAge() > s.getAge()) {
  5. return - 1; //新元素大于旧元素,就放左边
  6. } else if (news.getAge() < s.getAge()) {
  7. return 1; //新元素小于旧元素,就放右边
  8. } else {
  9. return news.getName().compareTo(s.getName()); //如果相同不存
  10. }
  11. /*旧元素 减 新元素,
  12. * 返回的数据:新元素则会使用旧元素的对比(大、小)
  13. * 如果大于:则把新元素放到右边(此时新元素是小的)
  14. * 如果小于:则把新元素放到左边(此时新元素是大的)
  15. */
  16. // int isAge = s.getAge() - news.getAge(); //相减不是大于就是小于或者等于
  17. // return isAge == 0 ? news.getName().compareTo(s.getName()) : isAge; // 如果年龄相等则用名字进行升序排序,如果名字相同则不存
  18. }
  19. };

 

Collections集合工具类

  • 二分查找
  • 最值
  • 元素的排序
  • 元素的替换
  • 最重要的是:可对非同步集合转成同步集合。
  • 等等...

集合转数组

和Collections集合工具类无关,集合转数组是通过Collection接口中的方法:

第一个方法返回后可能根据需求还得强转,通常用第二种方法:传入一个任意类型的(除基本类型)数组,就返回这个类型的数组。


  
  1. package com.bin.demo;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class Main {
  5. public static void main(String[] args) {
  6. List<Integer> list = new ArrayList<Integer>();
  7. list.add( 1);
  8. list.add( 2);
  9. list.add( 3);
  10. /*
  11. * 构造和集合相等长度的数组,如果构造的数组大小不合适集合的size,则会自动new相等长度的数组
  12. */
  13. Integer[] arr = list.toArray( new Integer[ list.size()]); //如果数组类型和集合元素类型不匹配,则发生java.lang.ArrayStoreException异常
  14. for ( int i : arr) {
  15. System.out.println(i);
  16. }
  17. }
  18. }
  19. 输出:
  20. 1
  21. 2
  22. 3

 

Arrays工具类(操作数组)

  • 任何类型的数组进行排序
  • 二分查找
  • 复制到新数组
  • 替换元素
  • 转换String
  • 数组转集合,注意事项:(转换后不支持对数组的增删)(如果数组元素是基本类型数据,则直接把数组引用当作集合元素。如果数组元素是引用类型数据,则把数组的每个元素当作集合元素存储)
  • 等等...

数组转集合注意


  
  1. package com.bin.demo;
  2. import java.util.Arrays;
  3. import java.util.List;
  4. public class Main {
  5. public static void main(String[] args) {
  6. int[] arr = { 1, 2, 3, 4, 5};
  7. List< int[]> aList = Arrays.asList(arr);
  8. // aList.add(new int[] {-1}); //异常: java.lang.UnsupportedOperationException
  9. System.out.println(aList.size()); //打印长度
  10. }
  11. }
  12. 输出:
  13. 1

 


转载:https://blog.csdn.net/qq_42470947/article/details/104764941
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场