java集合类类库的用途主要是用于 “保存对象” ,其可以被划分为两个不同的概念:
(1)Collection:它是一个独立元素的序列,这些元素通常都服从一条或多条规则。它的下面包含List和Set,List必须按照插入的顺序保存元素,可以保存重复的元素,而Set则不能有重复的元素。
(2)Map:是一组成对的 “键值对" 对象,允许通过 “键” 来查找 “值”。Map用于保存具有映射关系的数据,Map里保存着两组数据:key和value,它们都可以使任何引用类型的数据,但key不能重复。所以通过指定的key就可以取出对应的value。
(1)相同点:
两者都是容器,都用来存储多个数据。
(2)不同点:
1)长度区别:数组的长度是固定的,集合的长度可以通过扩容进行变化。
2)内容区别:数据可以存储基本数据类型(int, char, float等)和引用数据类型(类、 接口类型、 数组类型等),而集合只能存储引用数据类型。
3)元素区别:数组只能存储同一种类型,集合可以存储不同类型。
(1)Collection集合概述
1)是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素。
2)JDK 不提供此接口的任何直接实现.它提供更具体的子接口(如Set和List)实现。
(2)创建Collection集合的对象
以多态的方式创建,具体的实现类为ArrayList。
(3)Collection集合常用方法
方法名 | 说明 |
---|---|
boolean add(E e) | 添加元素 |
boolean remove(Object o) | 从集合中移除指定的元素 |
boolean removeIf(Object o) | 根据条件进行移除 |
void clear() | 清空集合中的元素 |
boolean contains(Object o) | 判断集合中是否存在指定的元素 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中元素的个数 |
(4)代码测试
public class CollectionTest {
public static void main(String[] args) {
//以多态的方式声明,具体的实现类为ArrayList
Collection<String> collection = new ArrayList<String>();
//add 添加数据
collection.add("aaa");
//remove 从集合中移除指定元素
collection.remove("aaa");
//removeIf 根据条件移除元素,当条件成立时该元素被移除
collection.removeIf(
(String s)->{
return s.length() == 3;
}
);
//clear 清空集合中的元素
collection.clear();
//contains 判断集合是否存在指定的元素,存在则返回true,否则返回false
collection.contains("aaa");
//isEmpty 判断集合是否为空,是则返回true,否则返回false
collection.isEmpty();
// size 表示该集合的长度
collection.size();
}
}
(1)List集合的概述和特点
1)List集合的概述
2)List集合的特点
(2)List集合常用的方法
方法名 | 说明 |
---|---|
void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
(3)List集合常用的子类及特点
(1)ArrayList:底层数据结构是数组,查询快,增删慢,线程不安全,效率高,可以存储重复元素
(2)LinkedList 底层数据结构是链表,查询慢,增删快,线程不安全,效率高,可以存储重复元素
List集合存储对象的遍历方式主要有以下三种(可根据自己实际需要选取遍历方式):
(1)使用迭代器遍历,集合特有的遍历方式
(2)使用普通for循环遍历,带有索引
(3)使用增强for循环,最方便的方式
public class ListTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("d");
list.add("a");
list.add("b");
list.add("c");
list.add("d");
//迭代器进行遍历
Iterator<String> it = list.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
//普通for循环方式
for (int i=0;i<list.size();i++){
String s=list.get(i);
System.out.println(s);
}
//加强for循环,foreach遍历方式
for (String s : list) {
System.out.println(s);
}
}
}
输出结果:
两种方式都一样,输出为:d a b c d
(1)ArrayList常用的特有的方法
方法名 | 说明 |
---|---|
public ArrayList() | 创建一个空的集合对象 |
public boolean add(E e) | 将指定的元素追加到此集合的末尾 |
public void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
public boolean remove(Object o) | 删除指定的元素,返回删除是否成功 |
public E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
public E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
public E get(int index) | 返回指定索引处的元素 |
public int size() | 返回集合中的元素的个数 |
(2)代码测试
1)当以List多态的方式声明,实现类为ArrayList时。ArrayList已经被向上转型为List,该对象只能调用List特有的方法而不能调用ArrayList中特有的方法。当你要用ArrayList中特有的方法时,则需要将其转型为对应的接口(ArrayList的接口),即参考(2)的代码测试,而不能将它们向上转型为通用的接口。
public class ListTest {
public static void main(String[] args) {
//当以List多态的方式声明,实现类为ArrayList时
List<String> list = new ArrayList<String>();
//add 添加数据。输出:索引为0的位置值为aaa
list.add("aaa");
//在此集合中的指定位置插入指定的元素。输出:索引为1的位置值为qqq
list.add(1,"qqq");
//remove 删除指定索引处的元素,返回被删除的元素。 输出:索引为0的值被删除
list.remove(0);
//set 修改指定索引处的元素,返回被修改的元素。输出:索引为0的值被修改为qqq
list.set(0, "qqq");
//get 返回指定索引处的元素。 输出:索引为0的值被获取
list.get(0);
}
}
2)当以ArrayList的方式声明,实现类为ArrayList时,因为ArrayList继承了List,故其不仅可以使用自身特有方法,也可以使用List的特有方法。
public class ListTest {
public static void main(String[] args) {
//以ArrayList为接口声明
ArrayList<String> array = new ArrayList<String>();
//add 添加数据。
array.add("aaa");
//remove 删除指定的元素,返回删除是否成功
array.remove("aaa");
//删除指定索引处的元素,返回被删除的元素
array.remove(1)
//set 修改指定索引处的元素,返回被修改的元素。输出:索引为0的值被修改为qqq
array.set(0, "qqq");
//get 返回指定索引处的元素。 输出:索引为0的值被获取
array.get(0);
//size 返回集合中的元素的个数
array.size();
}
}
3)ArrayList存储学生对象并遍历
案例需求
代码实现:
学生类
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
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 +
'}';
}
}
测试类
public class ArrayListTest {
public static void main(String[] args) {
//创建集合对象
ArrayList<Student> array = new ArrayList<Student>();
//创建学生对象
Student s1 = new Student("林青霞",30);
Student s2 = new Student("风清扬", 33);
Student s3 = new Student("张曼玉", 18);
//添加学生对象到集合之中
array.add(s1);
array.add(s2);
array.add(s3);
//遍历出数据,采用通用遍历方式
for(int i = 0; i< array.size(); i++){
Student s = array.get(i);
System.out.println(s.getName()+","+s.getAge());
}
//采用加强for循环foreach方式
for (Student value: array) {
System.out.println(value.getName()+","+value.getAge());
}
}
}
输出结果:
//两种输出方式一样
林青霞,30
风清扬,33
张曼玉,18
(1)LinkedList常用的特有的方法
方法名 | 说明 |
---|---|
public void addFirst(E e) | 在该列表开头插入指定的元素 |
public void addLast(E e) | 将指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFirst() | 从此列表中删除并返回第一个元素 |
public E removeLast() | 从此列表中删除并返回最后一个元素 |
(2)代码测试
1)当以List多态的方式声明,实现类为LinkedList时。和上述的ArrayList一样,LinkedList已经被向上转型为List,该对象只能调用List特有的方法而不能调用LinkedList中特有的方法。该代码测试和ArrayList一样,如下。
public class ListTest {
public static void main(String[] args) {
//当以List多态的方式声明,实现类为ArrayList时
List<String> list = new LinkedList<String>();
//add 添加数据。输出:索引为0的位置值为aaa
list.add("aaa");
//在此集合中的指定位置插入指定的元素。输出:索引为1的位置值为qqq
list.add(1,"qqq");
//remove 删除指定索引处的元素,返回被删除的元素。 输出:索引为0的值被删除
list.remove(0);
//set 修改指定索引处的元素,返回被修改的元素。输出:索引为0的值被修改为qqq
list.set(0, "qqq");
//get 返回指定索引处的元素。 输出:索引为0的值被获取
list.get(0);
}
}
2)当以LinkedList的方式声明,实现类为LinkedList时,因为LinkedList继承了List,故其不仅可以使用自身特有方法,也可以使用List的特有方法。
public class ListTest {
public static void main(String[] args) {
//当以List多态的方式声明,实现类为ArrayList时
LinkedList<String> list = new LinkedList<String>();
//addFirst 在该列表开头插入指定的元素
list.addFirst("qqq");
//addLast 将指定的元素追加到此列表的末尾
list.addLast("www");
//返回此列表中的第一个元素
list.getFirst();
//返回此列表中的最后一个元素
list.getLast();
//从此列表中删除并返回第一个元素
list.removeFirst();
//从此列表中删除并返回最后一个元素
list.removeLast();
}
}
(1)Set集合概述和特点
Set集合存储对象的遍历方式主要有以下两种(可根据自己实际需要选取遍历方式,其不能使用普通for循环遍历):
(1)使用迭代器遍历,集合特有的遍历方式
(2)使用增强for循环,最方便的方式
public class MySet1 {
public static void main(String[] args) {
//创建集合对象
Set<String> set = new TreeSet<>();
//添加元素
set.add("ccc");
set.add("aaa");
set.add("aaa");
set.add("bbb");
/**
*Set集合是没有索引的,所以不能使用通过索引获取元素的方法,该方法是错误的
for (int i = 0; i < set.size(); i++) {
}
*/
//遍历集合,迭代器方法遍历
Iterator<String> it = set.iterator();
while (it.hasNext()){
String s = it.next();
System.out.println(s);
}
System.out.println("-----------------------------------");
//加强for循环遍历
for (String s : set) {
System.out.println(s);
}
}
}
输出结果:
aaa
bbb
ccc
(1)TreeSet集合概述和特点
根据构造方法不同,其可以分为自然排序(无参构造)和比较器排序(有参构造),自然排序要求元素必须实现Compareable接口,并重写里面的compareTo()方法,元素通过比较返回的int值来判断排序序列,返回0说明两个对象相同,不需要存储;比较器排序需要在TreeSet初始化的时候传入一个实现Comparator接口的比较器对象,或者采用匿名内部类的方式new一个Comparator对象,重写里面的compare()方法;
(2)TreeSet集合基本使用
存储Integer类型的整数并遍历
public class TreeSetDemo01 {
public static void main(String[] args) {
//创建集合对象
TreeSet<Integer> ts = new TreeSet<Integer>();
//添加元素
ts.add(10);
ts.add(40);
ts.add(30);
ts.add(50);
ts.add(20);
ts.add(30);
//遍历集合
for(Integer i : ts) {
System.out.println(i);
}
}
}
输出结果:
为排序好的顺序结果
10 20 30 40 50
(3)自然排序Comparable的使用
自然排序(无参构造)要求元素必须实现Compareable接口,并重写里面的compareTo()方法,元素通过比较返回的int值来判断排序序列,返回0说明两个对象相同,不需要存储。
学生类
注意:自定义的学生类需要实现Comparable接口才能重写compareTo(T o)方法
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
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 +
'}';
}
/**
*重写接口中的compareTo方法
*/
@Override
public int compareTo(Student o) {
//按照对象的年龄进行排序
/**
*主要判断条件: 按照年龄从小到大排序,当result小于0时,则排序在前面,
*当result大于零时则排序到后面。this指向的是正在存储的函数,o表示
*已经存储过的函数(可包含多个函数),用正在存储的函数一个个和已经存储过的
*函数进行年龄比较
*/
int result = this.age - o.age;
/**
*次要判断条件: 年龄相同时,按照姓名的字母顺序排序
*下面的句子是一个三元运算符,判断当result等于0时(即表示两者年龄相同),
*则调用comparaTo函数比较名字的字母,否则直接输出result结果
*/
result = result == 0 ? this.name.compareTo(o.getName()) : result;
return result;
}
}
测试类
public class MyTreeSet2 {
public static void main(String[] args) {
//创建集合对象
TreeSet<Student> ts = new TreeSet<>();
//创建学生对象
Student s1 = new Student("zhangsan",28);
Student s2 = new Student("lisi",27);
Student s3 = new Student("wangwu",29);
Student s4 = new Student("zhaoliu",28);
Student s5 = new Student("qianqi",30);
//把学生添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
//遍历集合
for (Student student : ts) {
System.out.println(student);
}
}
}
输出结果为已经按顺序排序好的:
Student{name='lisi', age=27}
Student{name='zhangsan', age=28}
Student{name='zhaoliu', age=28}
Student{name='wangwu', age=29}
Student{name='qianqi', age=30}
(4)比较器排序Comparator的使用
比较器排序(有参构造)需要在TreeSet初始化的时候传入一个实现Comparator接口的比较器对象,或者采用匿名内部类的方式new一个Comparator对象,重写里面的compare()方法;
代码实现:
老师类
public class Teacher {
private String name;
private int age;
public Teacher() {
}
public Teacher(String name, int age) {
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 "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类
public class MyTreeSet4 {
public static void main(String[] args) {
//创建集合对象,重写compare方法,采用匿名内部类的方式new一个Comparator对象
TreeSet<Teacher> ts = new TreeSet<>(new Comparator<Teacher>() {
@Override
public int compare(Teacher o1, Teacher o2) {
//o1表示现在要存入的那个元素
//o2表示已经存入到集合中的元素
//主要条件
/**
*主要判断条件: 按照年龄从小到大排序,当result小于0时,则排序在前面,
*当result大于零时则排序到后面。this指向的是正在存储的函数,o表示
*已经存储过的函数(可包含多个函数),用正在存储的函数一个个和已经存储过的
*函数进行年龄比较
*/
int result = o1.getAge() - o2.getAge();
//次要条件
/**
*次要判断条件: 年龄相同时,按照姓名的字母顺序排序
*下面的句子是一个三元运算符,判断当result等于0时(即表示两者年龄相同),
*则调用comparaTo函数比较名字的字母,否则直接输出result结果
*/
result = result == 0 ? o1.getName().compareTo(o2.getName()) : result;
return result;
}
});
//创建老师对象
Teacher t1 = new Teacher("zhangsan",23);
Teacher t2 = new Teacher("lisi",22);
Teacher t3 = new Teacher("wangwu",24);
Teacher t4 = new Teacher("zhaoliu",24);
//把老师添加到集合
ts.add(t1);
ts.add(t2);
ts.add(t3);
ts.add(t4);
//遍历集合
for (Teacher teacher : ts) {
System.out.println(teacher);
}
}
}
输出结果:
Teacher{name='lisi', age=22}
Teacher{name='zhangsan', age=23}
Teacher{name='wangwu', age=24}
Teacher{name='zhaoliu', age=24}
(5)两种比较方式总结
(1)HashSet集合概述和特点
HashSet底层数据结构采用哈希表实现,元素无序且唯一,线程不安全,效率高,可以存储null元素,元素的唯一性是靠所存储元素类型是否重写hashCode()和equals()方法来保证的,如果没有重写这两个方法,则无法保证元素的唯一性。
Set的实现类的集合对象中不能够有重复元素,HashSet也一样使用了一种标识来确定元素的不重复,采用了哈希算法来保证HashSet中的元素是不重复的, 底层用 “数组+链表” 或者 “数组+红黑树” 存储数据,默认初始化容量16,加载因子0.75。
(2)哈希值
Object类中的hashCode()的方法是所有子类都会继承这个方法,这个方法会用Hash算法算出一个Hash(哈希)码值返回,HashSet会用Hash码值去和数组长度取模, 模(这个模就是对象要存放在数组中的位置)相同时才会判断数组中的元素和要加入的对象的内容是否相同,如果不同才会添加进去。
(3)哈希表结构
在JDK1.8以前(不包含1.8jdk版本)
存储结构采用的是数组+链表的形式。存储元素首先会使用hash()算法函数生成一个int类型hashCode的散列值(如图用数组下标代替哈希值),然后和已经所存储的元素的hashCode值进行比较,如果hashCode不相等,则所存储的两个对象一定不相等,此时存储当前的新的hashCode值处的元素对象(如黄色圆圈所存储的位置)。如果hashCode相等,存储元素的对象还是不一定相等,此时会调用equals()方法判断两个对象的内容是否相等,如果内容相等,那么就是同一个对象,无需存储;如果比较的内容不相等,那么就是不同的对象,就该存储了,此时就要采用哈希的解决地址冲突算法,在当前hashCode值处生成类似一个新的链表, 在同一个hashCode值的后面存储存储不同的对象,并且老元素将会被挂在新元素下面,这样就保证了元素的唯一性(如下图蓝色存储位置及其列表)。
加载因子0.75:
当数组里面存储了16*0.75=12个元素时,数组就会被自动扩容为原先的两倍。
当存储的链表结构少于等于8个时,采用的是 “数组+链表” 的结构,当存储列表的长度多余8个时,采用的是 “数组+红黑树” 的结构。后面存储元素的原理和上述相同,只是存储结构发生了改变。
(4)HashSet集合案例应用
代码实现
学生类
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
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;
}
//equals函数,当hashCode值一样时,用来判断两个对象的内容是否相等。相同则不存储,不同则存储
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
}
测试类
public class HashSetDemo02 {
public static void main(String[] args) {
//创建HashSet集合对象
HashSet<Student> hs = new HashSet<Student>();
//创建学生对象
Student s1 = new Student("林青霞", 30);
Student s2 = new Student("张曼玉", 35);
Student s3 = new Student("王祖贤", 33);
Student s4 = new Student("王祖贤", 33);
//把学生添加到集合
hs.add(s1);
hs.add(s2);
hs.add(s3);
hs.add(s4);
//遍历集合(增强for)
for (Student s : hs) {
System.out.println(s.getName() + "," + s.getAge());
}
}
}
输出结果:
王祖贤,33
张曼玉,35
林青霞,30
(1)List,Set都是继承自Collection接口。
(2)List和Set的特点和区别:
(3)ArrayList与LinkedList的区别和适用场景
当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。
(4)HashSet与TreeSet的区别和适用场景
HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。为快速查找而设计的Set,我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。
(1)Map集合概念
Map用于保存具有映射关系的数据,Map里保存着两组数据:key和value,它们都可以使任何引用类型的数据,但key不能重复。所以通过指定的key就可以取出对应的value。Map 没有继承 Collection 接口, Map 提供 key 到 value 的映射,可以通过 “键” 查找 “值”。一个 Map 中不能包含相同的 key ,每个 key 只能映射一个 value 。 Map 接口提供 3 种集合的视图, Map 的内容可以被当作一组 key 集合,一组 value 集合,或者一组 key-value 映射。
Map和Collection接口下的集合
Collection中的集合,元素是孤立存在的(理解为单身),向集合中存储元素采用一个个元素的方式存储。
Map中的集合,元素是成对存在的(理解为夫妻)。每个元素由键与值两部分组成,通过键可以找对所对应的值。
Collection中的集合称为单列集合,Map中的集合称为双列集合。
需要注意的是,Map中的集合不能包含重复的键,值可以重复;每个键只能对应一个值。
Map中常用的集合为HashMap集合、LinkedHashMap集合。
(2)Map集合常用方法
方法名 | 说明 |
---|---|
V put(K key,V value) | 添加元素 |
V remove(Object key) | 根据键删除键值对元素 |
void clear() | 移除所有的键值对元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
V get(Object key) | 根据键获取值 |
Set keySet() | 获取所有键的集合 |
Collection values() | 获取所有值的集合 |
Set |
获取所有键值对对象的集合 |
(3)代码测试
public class MapDemo02 {
public static void main(String[] args) {
//创建集合对象
Map<String,String> map = new HashMap<String,String>();
//V put(K key,V value):添加元素,"张无忌"是键名key,"赵敏"是值value,两者相互映射
map.put("张无忌","赵敏");
map.put("郭靖","黄蓉");
map.put("杨过","小龙女");
//V remove(Object key):根据键删除键值对元素
map.remove("郭靖")
//void clear():移除所有的键值对元素
map.clear();
//boolean containsKey(Object key):判断集合是否包含指定的键
map.containsKey("郭靖")
//boolean isEmpty():判断集合是否为空
map.isEmpty()
//int size():集合的长度,也就是集合中键值对的个数
map.size()
//输出集合对象
System.out.println(map);
//V get(Object key):根据键获取值
System.out.println(map.get("张无忌")); //输出结果为赵敏
System.out.println(map.get("张三丰")); //因没有这个键值,故输出结果为null
//Set keySet():获取所有键的集合
Set<String> keySet = map.keySet(); //输出结果为:张无忌,郭靖,杨过。
for(String key : keySet) {
System.out.println(key);
}
//Collection values():获取所有值的集合
Collection<String> values = map.values(); //输出结果为:赵敏,黄蓉,小龙女
for(String value : values) {
System.out.println(value);
}
}
}
(1)增强for循环遍历(使用较多)
(2)增强for结合Map.Entry(容量大时使用)
(3)迭代器遍历(根据keySet来遍历)
(4)迭代器遍历(根据entrySet来遍历)
public class MapDemo01 {
public static void main(String[] args) {
//创建集合对象
Map<String, String> map = new HashMap<String, String>();
//添加元素
map.put("张无忌", "赵敏");
map.put("郭靖", "黄蓉");
map.put("杨过", "小龙女");
/**
*(1)增强for循环遍历(使用较多)
*/
//获取所有键的集合。用keySet()方法实现
Set<String> keySet = map.keySet();
//遍历键的集合,获取到每一个键。用增强for实现
for (String key : keySet) {
//根据键去找值。用get(Object key)方法实现
String value = map.get(key);
System.out.println(key + ":" + value);
}
/**
*(2)增强for结合Map.Entry(容量大时使用)
*/
//获取所有键值对对象的集合
Set<Map.Entry<String, String>> entrySet = map.entrySet();
//遍历键值对对象的集合,得到每一个键值对对象
for (Map.Entry<String, String> me : entrySet) {
//根据键值对对象获取键和值
String key = me.getKey();
String value = me.getValue();
System.out.println(key + ":" + value);
}
/**
*(3)迭代器遍历(根据keySet来遍历)
*/
//获取所有键的集合。用keySet()方法实现
Set<String> keySet = map.keySet();
//遍历键的集合,获取到每一个键。用增强for实现
Iterator<String> keySets = keySet.iterator();
while(keySets.hasNext()) {
//遍历每一个键值,根据键去找值。用get(Object key)方法实现
String key = keySets.next();
String value = map.get(key);
System.out.println(key +":"+value);
}
/**
*(4)迭代器遍历(根据entrySet来遍历)
*/
//获取所有键值对对象的集合
Iterator<Map.Entry<String, String>> entries = map.entrySet().iterator();
while (entries.hasNext()){
//根据键值对对象获取键和值
Map.Entry<String,String> maps = entries.next();
String key = maps.getKey();
String value = maps.getValue();
System.out.println(key+":"+value);
}
}
}
输出结果:
杨过:小龙女
郭靖:黄蓉
张无忌:赵敏
(1)HashMap集合概述和特点
(2)HashMap工作原理
HashMap 数据结构为 “数组+链表”,其中:链表的节点存储的是一个 Entry 对象,每个Entry 对象存储四个属性(hash,key,value,next)。如下图可知,HashMap整体是一个数组,数组每一个位置都是一个链表,并且链表每个节点中的value值既是我们存储的Object。
(3)HashMap集合案例
学生类
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
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;
}
/**
*重写equal方法
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
/**
*重写hashCode方法
*/
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
}
测试类
public class HashMapDemo {
public static void main(String[] args) {
//创建HashMap集合对象
HashMap<Student, String> hm = new HashMap<Student, String>();
//创建学生对象
Student s1 = new Student("林青霞", 30);
Student s2 = new Student("张曼玉", 35);
Student s3 = new Student("王祖贤", 33);
Student s4 = new Student("王祖贤", 33);
//把学生添加到集合
hm.put(s1, "西安");
hm.put(s2, "武汉");
hm.put(s3, "郑州");
hm.put(s4, "北京");
//遍历集合
Set<Student> keySet = hm.keySet();
for (Student key : keySet) {
String value = hm.get(key);
System.out.println(key.getName() + "," + key.getAge() + "," + value);
}
}
}
输出结果:
王祖贤,33,北京
张曼玉,35,武汉
林青霞,30,西安
(1)TreeMap集合概述和特点
(注:底层结构、自然排序和比较器排序等可以参考TreeSet,这里就不在详细介绍)
(2)TreeMap集合案例
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
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
public int compareTo(Student o) {
//按照年龄进行排序
int result = o.getAge() - this.getAge();
//次要条件,按照姓名排序。
result = result == 0 ? o.getName().compareTo(this.getName()) : result;
return result;
}
}
测试类:
public class Test1 {
public static void main(String[] args) {
// 创建TreeMap集合对象
TreeMap<Student,String> tm = new TreeMap<>();
// 创建学生对象
Student s1 = new Student("xiaohei",23);
Student s2 = new Student("dapang",22);
Student s3 = new Student("xiaomei",22);
// 将学生对象添加到TreeMap集合中
tm.put(s1,"江苏");
tm.put(s2,"北京");
tm.put(s3,"天津");
// 遍历TreeMap集合,打印每个学生的信息
//获取所有键的集合。用keySet()方法实现
Set<Student> keySet = tm.keySet();
//遍历键的集合,获取到每一个键。用增强for实现
for (Student key : keySet) {
//根据键去找值。用get(Object key)方法实现
String value = tm.get(key);
System.out.println(key + ":" + value);
}
}
}
输出结果:
Student{name='xiaohei', age=23}:江苏
Student{name='xiaomei', age=22}:天津
Student{name='dapang', age=22}:北京
(1)list、Map、Set遍历方式总结
(2)Java集合超详解
(3)黑马Java学习资料
(4)java笔记-Map的用法
(5)Java中的Map集合
(6)10分钟拿下HashMap
这次写的关于Java集合的博客是因为在学习项目过程中用到了HashMap,以前学习过程中学得比较泛,对这List、Set和Map概念混淆在一起,现今整理了一下概念及其基础的用法,待以后深入学习之后再继续学习和记录集合中更底层的知识。