Java集合框架(二)
泛型
泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?
顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法
泛型类
语法:
class 类名称 <泛型标识:T、K、E、V等>{
泛型标识 变量名;
}
【演示】
package com.gather.generics;
public class GenericsDemo01<T> {
private T name;// name变量的类型是T类型
public GenericsDemo01(T name) {// 泛型类的构造方法(泛型作为方法的参数)
this.name = name;
}
public T showName() {// 泛型作为方法的返回值
return this.name;
}
}
package com.gather.generics;
public class Test01 {
public static void main(String[] args) {
GenericsDemo01<String> s1 = new GenericsDemo01<String>("张三");
String str = s1.showName();
System.out.println(str);
GenericsDemo01<Integer> s2 = new GenericsDemo01<Integer>(1234);
Integer ite = s2.showName();
System.out.println(ite);
}
}
执行结果:
张三
1234
注意:1. 泛型只能使用引用类型
2. 不用泛型类型对象之间不能相互赋值
泛型方法
泛型类:是在实例化类的时候指明泛型的具体类型;
泛型方法:是在调用方法的时候指明泛型的具体类型
泛型方法定义规则:
- 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前。
- 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
- 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
- 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。
【演示】
package com.gather.generics;
public class GnericsDemo02 {
// 无返回值的泛型方法
public static <T> void print(T input) {
System.out.println(input);
}
// 有返回值的泛型方法
public static <T> boolean compare(T a, T b) {
if (a.equals(b)) {
return true;
}
return false;
}
public static void main(String[] args) {
// 创建不同类型的对象
Integer i = new Integer(1);
Integer j = new Integer(8);
Character c = new Character('A');
String str = "java";
print(i);
print(c);
print(str);
System.out.println(compare(i, j));
}
}
执行结果:
1
A
java
false
泛型接口
语法:
interface 接口名 <泛型标识:T、K、E、V等> {
泛型标识 变量名;
}
【演示】
package com.gather.generics;
public interface GenericsDemo03<T> {
String name = "张三";
T show(T t);
void print(T t);
}
该接口有两种实现类有以下两种表示方法
【第一种:在实现类中确定泛型】
public class GenericsRealize1 implements GenericsDemo03 <String>{
@Override
public String show(String s) {
if (s.equals("java")) {
return "yes";
}
return "No";
}
@Override
public void print(String s) {
System.out.println(s);
}
}
public class Test02 {
public static void main(String[] args) {
GenericsRealize1 g = new GenericsRealize1();
String str1 = g.show("java");
String str2 = g.show("python");
System.out.println(str1);
System.out.println(str2);
g.print("hello");
}
}
执行结果:
yes
No
hello
【第二种:在实现类中不确定泛型,使用泛型实现类】
package com.gather.generics;
public class GenericsRealize2<T> implements GenericsDemo03<T> {
@Override
public T show(T t) {
if (t.equals("java")) {
System.out.println("hahahaha");
}
return t;
}
@Override
public void print(T t) {
System.out.println(t);
}
}
public class Test03 {
public static void main(String[] args) {
GenericsRealize2<Integer> g1 = new GenericsRealize2<Integer>();
System.out.println(g1.show(123));
g1.print(100);
GenericsRealize2<String> g2 = new GenericsRealize2<String>();
System.out.println(g2.show("java"));
g2.print("张三");
new GenericsRealize2<Character>().print('A');
new GenericsRealize2<Double>().print(3.14);
}
}
执行结果:
123
100
hahahaha
java
张三
A
3.14
泛型集合
概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致
特点:
- 编译时即可检查,而非运行时抛出异常
- 访问时,不必类型转换(拆箱)
- 不同泛型之间不能相互赋值,泛型不存在多态
package com.gather.generics;
import java.util.ArrayList;
public class Demo {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<String>();
//ArrayList arrayList = new ArrayList();其类型是Object类
arrayList.add("张三");
arrayList.add("王五");
arrayList.add(0, "李四");
// arrayList.add(123);123不是String类型,报错
for (String s : arrayList) {
System.out.println(s);
}
}
}
执行结果:
李四
张三
王五
Set接口
特点:无序、无下标、元素不可重复
方法:全部继承自Collection中的方法,增、删、遍历、判断与collection一致
【演示】
package com.gather.set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Demo01 {
public static void main(String[] args) {
Set<String> set = new HashSet<String>();// 实例化集合,Set是接口必须利用其实现类创建对象
set.add("张三");// 添加元素
set.add("李四");
set.add("王五");
set.add("赵六");
//set.add(0, "赵六");不能通过下标添加元素(Set无下标)
//set.add("王五");不能添加相同的元素
System.out.println(set.size());
System.out.println(set.toString());// 元素是无序的
set.remove("张三");// 删除元素
System.out.println(set.contains("李四"));// 判断集合中是否包含"李四"
System.out.println(set.isEmpty());// 判断集合是否为空
/*
遍历元素:1.利用增强for;2.利用迭代器Iterator
*/
for (String str : set) {
System.out.println(str);
}
Iterator<String> it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
执行结果:
4
[李四, 张三, 王五, 赵六]
true
false
李四
王五
赵六
李四
王五
赵六
HashSet 类
存储结构:哈希表(数组+链表\红黑树)
数组结构:把元素进行了分组(相同哈希值的元素是一组)
链表/红黑树结构:把相同哈希值的元素连到一起(如果链表的长度超过了8位,那么就会把链转换位红黑树(提高查询的速度))
存储过程:(重复依据)
- 先根据hashCode计算保存的位置(数组位置),如果位置为空,直接保存,若不为空,进行第二步
- 再执行equals方法,如果equals为true,则认为是重复,重复的元素不会被添加,若为false则形成链表
基于hashCode计算元素存放位置,当存入元素的哈希码相同时,会调用equals进行确认,如果结果为true,则拒绝后者存入
重写hashCode方法时31的利用:
- 利用31这个质数,减少散列冲突
- 31提高执行效率
31 * i = (i << 5) - i
转为移位操作
【演示】
package com.gather.hashset;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if (o.getClass() != this.getClass()) {
return false;
}
if (o instanceof Student) {
Student student = (Student) o;
if (this.name.equals(student.name) && this.age == student.age) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + age;
return result;
}
@Override
public String toString() {
return "{" + this.name + "," + this.age + "}";
}
}
package com.gather.hashset;
import java.util.HashSet;
import java.util.Iterator;
public class Demo {
public static void main(String[] args) {
Student s1 = new Student("张三", 10);
Student s2 = new Student("李四", 10);
Student s3 = new Student("王五", 10);
Student s4 = new Student("赵六", 10);
HashSet<Student> hashset = new HashSet<Student>();
hashset.add(s1);
hashset.add(s2);
hashset.add(s3);
hashset.add(s4);
//hashset.add(s1);重复的元素不会被添加
//hashset.add(new Student("张三", 10));若Student类中未重写hashCode和equals方法,则会添加成功
hashset.remove(new Student("李四", 10));// 等价于hashset.remove(s2);(Student类中重写了hashCode和equals方法)
System.out.println(hashset.size());
System.out.println(hashset.contains(new Student("赵六", 10)));//等价于hashset.contains(s4);(Student类中重写了hashCode和equals方法)
/*
遍历元素:1.利用增强for; 2.利用迭代器Iterator
*/
for (Student s : hashset) {
System.out.println(s);
}
Iterator<Student> it = hashset.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
System.out.println(hashset.toString());
hashset.clear();// 清空集合
System.out.println(hashset.isEmpty());
}
}
执行结果:
3
true
{王五,10}
{赵六,10}
{张三,10}
{王五,10}
{赵六,10}
{张三,10}
[{王五,10}, {赵六,10}, {张三,10}]
true
TreeSet类
TreeSet和HashSet的区别在于, HashSet不可以进行排序,TreeSet可以进行排序, 默认使用字典顺序排序, 也可以进行自定义排序。
TreeSet两种排序方式:
-
让自定义的类实现Comparable 接口
-
1.Student类中实现 Comparable< T >接口
2.重写Comparable接口中的CompareTo方法
-
-
创建一个比较类,并让其实现Comparator接口
-
1.构造一个新的空 TreeSet,它根据指定比较器进行排序
2.重写Comparator接口中的Compare方法
-
存储结构:红黑树
特点:
- 基于排列顺序实现元素不重复
- 实现SortedSet接口,对集合元素自动排序
- 元素对象的类型必须实现Comparable接口,指定排序规则
- 通过CompareTo方法确定是否为重复元素
注:其中元素对象的类型必须实现Comparable接口有两种方式。第一种是在一个实现类中实现Comparable接口,在该类中重写CompareTo方法;第二种是在创建TreeSet集合时就指定比较规则,使用匿名内部类
自定义的类实现Comparable 接口
【演示】
public class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "{" + this.name + "," + this.age + "}";
}
@Override
public int compareTo(Person o) {
int a = this.name.compareTo(o.name);// 若a等于0,则说明name相同
int b = this.age - o.age;// 若b等于0,则说明age相同
return a == 0 ? b : a;// 如果a等于0,就返回b的值,否则返回a的值(先对名字进行排序,再对年龄进行排序)
}
}
package com.gather.treeset;
import java.util.Iterator;
import java.util.TreeSet;
public class Demo01 {
public static void main(String[] args) {
TreeSet<Person> p = new TreeSet();
Person p1 = new Person("afang", 5);
Person p2 = new Person("afang", 8);// p1和p2的name相同,比较age
Person p3 = new Person("xiaoming", 3);
Person p4 = new Person("zhangsan", 8);
Person p5 = new Person("xy", 5);
p.add(p1);// 添加元素
p.add(p2);
p.add(p3);
p.add(p4);
p.add(p5);
//p.add(new Person("xy",5));无法添加重复的元素
System.out.println("元素个数:" + p.size());
System.out.println(p.toString());
p.remove(new Person("xy", 5));// 删除元素(实体中重写了compareTo方法)等同p.remove(p5)
System.out.println(p.contains(new Person("zhangsan", 8)));// 判断是否包含(实体中重写了compareTo方法)等同p.contains(p4)
/*
元素遍历:1.增强for
2.迭代器Iterator
*/
System.out.println("-----for-----");
for (Person person : p) {
System.out.println(person);
}
System.out.println("-----Iterator-----");
Iterator<Person> it = p.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
执行结果:
元素个数:5
[{afang,5}, {afang,8}, {xiaoming,3}, {xy,5}, {zhangsan,8}]
true
-----for-----
{afang,5}
{afang,8}
{xiaoming,3}
{zhangsan,8}
-----Iterator-----
{afang,5}
{afang,8}
{xiaoming,3}
{zhangsan,8}
创建一个比较类,并让其实现Comparator接口
【演示】
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "{" + this.name + "," + this.age + "}";
}
}
package com.gather.treeset;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class Demo02 {
public static void main(String[] args) {
TreeSet<Student> t = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int x = o1.getName().length() - o2.getName().length();// 若x等于0,则说明o1、o2的name长度一样
int y = o1.getAge() - o2.getAge();// 若y等于0,则说明o1、o2的age相等
return x == 0 ? y : x;// 如果x等于0,就返回y的值,否则返回x的值(先对名字长度排序,再对年龄进行排序)
}
});
Student s1 = new Student("张三", 3);
Student s2 = new Student("王五", 4);
Student s3 = new Student("刘德华", 25);
Student s4 = new Student("梁朝伟", 25);
Student s5 = new Student("欧阳娜娜", 18);
t.add(s1);
t.add(s2);// s1和s2的name长度相同,按age大小排序
t.add(s3);
t.add(s4);// s3和s4的name长度相同,age相等,所以s4会被认为是重复的元素,不能添加
t.add(s5);
System.out.println("元素个数:"+t.size());
System.out.println(t.toString());
t.remove(new Student("王五", 4));// 删除元素(重写了compare方法)等同t.remove(s2)
System.out.println(t.contains(new Student("欧阳娜娜", 18)));// 判断是否包含(重写了compare方法)等同t.contains(s5)
/*
元素遍历:1.增强for
2.迭代器Iterator
*/
System.out.println("-----for-----");
for (Student student : t) {
System.out.println(student);
}
System.out.println("-----Iterator-----");
Iterator<Student> it = t.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
执行结果:
元素个数:4
[{张三,3}, {王五,4}, {刘德华,25}, {欧阳娜娜,18}]
true
-----for-----
{张三,3}
{刘德华,25}
{欧阳娜娜,18}
-----Iterator-----
{张三,3}
{刘德华,25}
{欧阳娜娜,18}
Map接口
Map接口的特点
- 用于存储任意键值对(key , value)
- 键:无序、无下标、不允许重复(唯一)
- 值:无序、无下标、允许重复
方法 | 描述 |
---|---|
V put(K key, V value) | 将指定的值与该映射中的指定键相关联(可选操作) |
V remove(Object key) | 如果存在(从可选的操作),从该地图中删除一个键的映射 |
default boolean replace(K key, V oldValue,V newValue) | 仅当当前映射到指定的值时,才能替换指定键的条目 |
boolean containsKey(Object key) | 如果此映射包含指定键的映射,则返回 true |
boolean containsValue(Object value) | 如果此地图将一个或多个键映射到指定的值,则返回 true |
V get(Object key) | 返回到指定键所映射的值 |
Set< K > keySet() | 返回此地图中包含的键的Set视图 |
Set<Map.Entry<K,V>> entrySet() | 返回此地图中包含的映射的Set视图 |
Map.Entry<K,V>接口
方法 | 描述 |
---|---|
K getKey() | 返回与此条目相对应的键 |
V getValue() | 返回与此条目相对应的值 |
【演示】
package com.gather.map;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Demo01 {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<Integer, String>();// 通过其实现类创建Map集合
map.put(1, "中国");// 添加元素
map.put(2, "美国");
map.put(3, "英国");
map.put(4, "法国");
map.put(2, "俄罗斯");// 添加相同键的元素,原有值将被替换(美国会被俄罗斯替换)
System.out.println("元素的个数为:" + map.size());
System.out.println(map.toString());
map.replace(4, "法国", "日本");// 替换键为4的值为"日本"
map.remove(3);// 删除键为3的元素
System.out.println("删除后:" + map.toString());
System.out.println(map.containsKey(1));// 判断是否包含键为1的元素
map.containsValue("中国");// 判断是否包含值为"中国"的元素
/*
Map集合的遍历:1.keySet() 2.entrySet()
*/
System.out.println("-------keySet()-------");
Set<Integer> keyset = map.keySet();// map.keySet()返回的是键的Set集合,即可以用Set集合的遍历方法
for (Integer key : keyset) {
System.out.println(key + "=" + map.get(key));// 其值通过map.get(key)获取
}
System.out.println("-------entrySet()-------");
Set<Map.Entry<Integer, String>> entries = map.entrySet();// map.entrySet()的返回的是映射(包含键值)的Set集合(entry映射对)
for (Map.Entry<Integer, String> entry : entries) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
}
}
执行结果:
元素的个数为:4
{1=中国, 2=俄罗斯, 3=英国, 4=法国}
删除后:{1=中国, 2=俄罗斯, 4=日本}
true
-------keySet()-------
1=中国
2=俄罗斯
4=日本
-------EntrySet()-------
1=中国
2=俄罗斯
4=日本
HashMap 类
HashMap 实现了 Map 接口,根据键的 HashCode 值存储数据,具有很快的访问速度。HashMap 是无序的,即不会记录插入的顺序。
存储结构:哈希表(数组+链表+红黑树)
【演示】
public class Student {
private String name;
private int stuNum;
public Student(String name, int stuNum) {
this.name = name;
this.stuNum = stuNum;
}
public String getName() {
return name;
}
public int getStuNum() {
return stuNum;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
if (getStuNum() != student.getStuNum()) return false;
return getName().equals(student.getName());
}
@Override
public int hashCode() {
int result = getName().hashCode();
result = 31 * result + getStuNum();
return result;
}
@Override
public String toString() {
return "[" + this.name + "," + this.stuNum + "]";
}
}
package com.gather.hashmap;
import java.util.HashMap;
import java.util.Map;
public class Demo01 {
public static void main(String[] args) {
HashMap<Student, String> students = new HashMap<Student, String>();// 创建集合
Student s1 = new Student("张三", 1001);
Student s2 = new Student("李四", 1002);
Student s3 = new Student("王五", 1003);
Student s4 = new Student("赵六", 1004);
students.put(s1, "3班");// 添加元素
students.put(s2, "3班");// 键不能重复,值可以重复
students.put(s3, "4班");
students.put(s4, "5班");
/*
students.put(new Student("赵六", 1004), "3班");
这对键值能够添加成功,但是其键相同,不满足HashMap的特点,
所以需在Student类重写equals和hashCode方法,避免键相同的重复添加
*/
students.put(new Student("赵六", 1004), "3班");// 重写equals和hashCode方法后,元素不会重复添加,但是其值会被替换("5班"被替换为"3班")
System.out.println("元素个数为:" + students.size());
System.out.println(students.toString());
System.out.println(students.containsKey(new Student("王五", 1003)));// 若Student类未重写equals和hashCode方法,则返回false
// 遍历1:keySet()
System.out.println("-------keySet()-------");
for (Student s : students.keySet()) {
System.out.println(s + "=" + students.get(s));
}
// 遍历2:entrySet()
System.out.println("-------entrySet()-------");
for (Map.Entry<Student, String> entry : students.entrySet()) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
}
}
执行结果:
元素个数为:4
{[李四,1002]=3班, [赵六,1004]=3班, [王五,1003]=4班, [张三,1001]=3班}
true
-------keySet()-------
[李四,1002]=3班
[赵六,1004]=3班
[王五,1003]=4班
[张三,1001]=3班
-------entrySet()-------
[李四,1002]=3班
[赵六,1004]=3班
[王五,1003]=4班
[张三,1001]=3班
HashMap源码分析总结:
- HashMap刚创建时,table=null,size=0,节省空间,当添加第一个元素时,table容量调整为16
- 当元素个数大于阈值(16*0.75 = 12)时,会进行扩容,扩容后的大小为原来的两倍,目的是减少调整元素的个数
- jdk1.8 当每个链表长度 >8 ,并且数组元素个数 ≥64时,会调整成红黑树,目的是提高效率
- jdk1.8 当链表长度 <6 时 调整成链表
- jdk1.8 以前,链表时头插入,之后为尾插入
Hashtable类
线程安全,运行效率慢;不允许null作为key或是value
Properties类
hashtable的子类,要求key和value都是string,通常用于配置文件的读取
TreeMap类
实现了SortedMap接口(是map的子接口),可以对key自动排序
TreeSet是一个有序集合,可以以任意顺序将元素插入到集合中,在对集合进行遍历的时候,每个元素将自动按照排序后的顺序呈现。底层使用的是二叉树(更具体点是红黑树)实现,对于元素之间排序,如果不指定自定义的比较器Comparator,那么插入的对象必须实现Comparable接口,元素按照实现此接口的compareTo()方法去排序。如果指定了自定义的比较器Comparator,优先使用Comparator去对元素进行排序。比较规则决定了元素是否可以重复,以及元素的排序结果。
TreeSet 底层实际使用的存储容器就是 TreeMap。与 HashSet 完全类似的是,TreeSet 里绝大部分方法都是直接调用 TreeMap 的方法来实现的
TreeMap两种排序方式:
-
让自定义的类实现Comparable 接口
-
1.Student类中实现 Comparable< T >接口
2.重写Comparable接口中的CompareTo方法
-
-
创建一个比较类,并让其实现Comparator接口
-
1.构造一个新的空 TreeMap,它根据指定比较器进行排序
2.重写Comparator接口中的Compare方法
-
自定义的类实现Comparable 接口
【演示】
public class Student implements Comparable<Student> {
private String name;
private int stuNum;
public Student(String name, int stuNum) {
this.name = name;
this.stuNum = stuNum;
}
@Override
public int compareTo(Student o) {
int x = this.stuNum - o.stuNum;// 若x等于0,则说明他们的学号相同
return x;// 对学号进行排序
}
@Override
public String toString() {
return "[" + this.name + "," + this.stuNum + "]";
}
}
package com.gather.treemap;
import java.util.Map;
import java.util.TreeMap;
public class Demo01 {
public static void main(String[] args) {
TreeMap<Student, String> students = new TreeMap<Student, String>();// 创建集合
Student s1 = new Student("张三", 1001);
Student s2 = new Student("李四", 1032);
Student s3 = new Student("王五", 1013);
Student s4 = new Student("赵六", 1024);
students.put(s1, "3班");// 添加元素
students.put(s2, "3班");// 键不能重复,值可以重复
students.put(s3, "4班");
students.put(s3, "8班");// s3不会被重复添加,但是其值会被替换("4班"会被替换为"8班"),因为Student类中重写了CompareTo方法
students.put(s4, "5班");
students.put(new Student("赵六", 1024), "1班");// 添加失败,但是会替换值("5班"会被替换为"1班"),因为Student类中重写了CompareTo方法
System.out.println("元素个数为:" + students.size());
System.out.println(students.toString());
System.out.println(students.containsKey(new Student("赵六", 1024)));// true,因为Student类中重写了CompareTo方法
// 遍历1:keySet()
System.out.println("-------keySet()-------");
for (Student s : students.keySet()) {
System.out.println(s + "=" + students.get(s));
}
// 遍历2:entrySet()
System.out.println("-------entrySet()-------");
for (Map.Entry<Student, String> entry : students.entrySet()) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
}
}
执行结果:
元素个数为:4
{[张三,1001]=3班, [王五,1013]=8班, [赵六,1024]=1班, [李四,1032]=3班}
true
-------keySet()-------
[张三,1001]=3班
[王五,1013]=8班
[赵六,1024]=1班
[李四,1032]=3班
-------entrySet()-------
[张三,1001]=3班
[王五,1013]=8班
[赵六,1024]=1班
[李四,1032]=3班
创建一个比较类,并让其实现Comparator接口
【演示】
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "[" + this.name + "," + this.age + "]";
}
}
package com.gather.hashmap;
import java.util.Comparator;
import java.util.TreeMap;
public class Demo02 {
public static void main(String[] args) {
TreeMap<Person, Character> treeMap = new TreeMap<Person, Character>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
int x = o1.getName().length() - o2.getName().length();
int y = o1.getAge() - o2.getAge();
return x == 0 ? y : x;// 先对名字长度排序,若名字长度一样,则按年龄大小排序
}
});
Person p1 = new Person("张三", 16);
Person p2 = new Person("孙悟空", 18);
Person p3 = new Person("欧阳娜娜", 23);
Person p4 = new Person("李四", 20);
treeMap.put(p1, 'A');
treeMap.put(p2, 'A');
treeMap.put(p3, 'B');
treeMap.put(p4, 'D');
System.out.println("元素个数为:" + treeMap.size());
System.out.println(treeMap.toString());
System.out.println(treeMap.containsKey(new Person("欧阳娜娜", 23)));// true,重写了compare方法等同treeMap.containsKey(p3)
}
}
执行结果:
元素个数为:4
{[张三,16]=A, [李四,20]=D, [孙悟空,18]=A, [欧阳娜娜,23]=B}
true
Collections工具类
方法 | 描述 |
---|---|
public static <T extends Comparable<? super T>> void sort(List< T > list) | 根据其元素的natural ordering对指定的列表进行排序 |
public static < T > int binarySearch(List<? extends T> list,T key,Comparator<? super T> c) | 使用二叉搜索算法搜索指定对象的指定列表 |
public static < T > void copy(List<? super T> dest, List<? extends T> src) | 将所有元素从一个列表复制到另一个列表中 |
public static void reverse(List<?> list) | 反转指定列表中元素的顺序 |
public static void shuffle(List<?> list) | 使用指定的随机源随机排列指定的列表 |
【演示】
package com.gather.collections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Demo01 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(10);
list.add(88);
list.add(24);
list.add(66);
System.out.println("排序之前:" + list.toString());
Collections.sort(list);// 排序
System.out.println("排序之后:" + list.toString());
System.out.println(Collections.binarySearch(list, 88));// 利用二分法查找88的下标
List<Integer> list2 = new ArrayList<Integer>();
for (int i = 0; i < list.size(); i++) {
list2.add(0);
}
Collections.copy(list2, list);// 复制元素是必须保证两个集合大小一样
System.out.println("list2复制:" + list2);
Collections.reverse(list);// 反转
System.out.println("反转:" + list.toString());
Collections.shuffle(list);// 打乱
System.out.println("打乱:" + list.toString());
}
}
执行结果:
排序之前:[10, 88, 24, 66]
排序之后:[10, 24, 66, 88]
3
list2复制:[10, 24, 66, 88]
反转:[88, 66, 24, 10]
打乱:[24, 66, 10, 88]
补充:数组与集合之间的转换
package com.gather.collections;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Demo02 {
public static void main(String[] args) {
/*
list转换成数组
数组的大小必须小于集合的大小,否则多余的数组空间将赋默认值
*/
List<Integer> list = new ArrayList<Integer>();
list.add(10);
list.add(88);
list.add(24);
list.add(66);
Integer[] arr1 = list.toArray(new Integer[0]);// 此处Integer[0]中的0小于集合大小的4
Integer[] arr2 = list.toArray(new Integer[8]);// 此处Integer[8]中的8大于集合大小的4,其余数组空间赋默认值
System.out.println(arr1.length);
System.out.println("arr1数组:" + Arrays.toString(arr1));
System.out.println("arr2数组:" + Arrays.toString(arr2));
/*
数组转换为集合
集合为受限集合,不能做添加、删除操作
把基本类型数组转换为集合时,需要修改为相应的包装类
*/
Integer[] array = {1, 3, 6, 8, 2};
List<Integer> list2 = Arrays.asList(array);
System.out.println("集合:" + list2.toString());
}
}
执行结果:
4
arr1数组:[10, 88, 24, 66]
arr2数组:[10, 88, 24, 66, null, null, null, null]
集合:[1, 3, 6, 8, 2]
集合总结
集合的概念:对象的容器,和数组类似,定义了对多个对象进行操作的常用方法。
-
List集合:
有序、有下标、元素可以重复。(ArrayList、LinkedList、Vector). -
Set集合:
无序、无下标、元素不可重复。(HashSet、TreeSet)
-
Map集合:
存储一对数据,无序、无下标,键不可重复,值可重复。(HashMap、HashTable、TreeMap). -
Collections集合工具类
定义了除了存取以外的集合常用方法。