集合的理解和好处
-
首先我们前面的学习中保存多个数据用的是数组,那么数组有什么不足的地方呢。
-
数组:
- 长度开始时必须指定,而且一旦指定,不能更改。
- 保存的必须为同一类型元素。
- 使用数组进行增加/删除元素的示意代码--比较麻烦
-
写出Person数组扩容的示意图
Person[] pers = new Person[1];
pers[0] = new Person;
- 怎样增加新的Person对象
Person[] person2 = new Person[person.length+1];//创建一个新的数组,长度比之前的长
for (int i=0;i<=person.length;i++){//拷贝person数组的元素大到到person2
person2[i] = person[i];
}
person2[person2.length-1] =new Person();//添加新的对象
}
-
集合:
- 可以动态的保存任意多个对象,使用起来比较方便。
- 提供了一系列方便的操作对象的方法:add(添加),remove(删除),set(修改),get(获得)等。
- 使用了集合添加,删除新元素的示意代码更加简洁名了。
集合框架体系
- Java的集合类有很多,主要分为两大类(单列集合,双列集合)如图要背下来。
- Collection(单列集合):存放的是单个单个的元素。
- Map(双列集合):存放的是键值对(Key-Value)形式。
collection
-
Collection接口实现类的特点
public interface Collection extends Iterable
-
Collection实现子类可以存放多个元素,每个元素可以是Object。
-
有些Collection的实现类,可以存放重复的元素,有些不可以。
-
有些Collection的实现类,有些是有序的(List),有些不是有序的(Set)。
有序:存放的顺序和取出的顺序保持一致。
-
Collection接口没有直接的实现子类,是通过它的子接口Set和List来实现的。
-
-
介绍Collection接口常用的方法,这里使用它的子类ArrayList来演示:
- add();添加单个元素。
- remove();删除指定元素。
- contains();查找元素是否存在。
- size();获取元素个数。
- isEmpty();判断是否为空。
- clear();清空。
- addAll();添加多个元素。
- containsAll();查找多个元素是否都存在。
- removeAll();删除多个元素。
public class CollectionWaysTest {
public static void main(String[] args) {
new CollectionWaysTest().m1();
}
public void m1(){
ArrayList<Object> list = new ArrayList<>();
//1. add();添加单个元素。
list.add("tom");//添加字符串
list.add(100);//添加整型,这里会自动装箱add(new Integer(100));
list.add(true);//添加布尔型,这里会自动装箱
System.out.println(list);//结果:[tom, 100, true]
//2. remove();删除指定元素。
//第一种方式:list.remove(Object obj);
list.remove("tom");//按照对象名删除指定元素.
//第二种方式:list.remove(int num);
list.remove(0);//按照数组下标删除指定元素.
System.out.println(list);//结果:[true]
//3. contains(Object obj);查找元素是否存在。
System.out.println(list.contains("100"));//结果:false
//4. size();获取元素个数(长度)。
System.out.println(list.size());//结果:1
//5. isEmpty();判断是否为空。
System.out.println(list.isEmpty());//结果:false
//6. clear();清空元素。
list.clear();
//7. addAll(Collection col);添加多个元素。可以传入任何只要是实现了Collection接口的子类对象。
ArrayList<Object> newList = new ArrayList<>();
newList.add("newTom");
newList.add("new100");
newList.add("newTrue");
list.addAll(newList);
System.out.println(list);//结果:[newTom, new100, newTrue]
//8. containsAll();查找多个元素是否都存在。可以传入任何只要是实现了Collection接口的子类对象。
System.out.println(list.containsAll(newList));//结果:true
//9. removeAll();删除多个元素。可以传入任何只要是实现了Collection接口的子类对象。
list.removeAll(newList);
System.out.println(list);//结果:[]
}
}
Collection接口遍历元素
Collection接口遍历元素方式1(使用Iterator(迭代器))
- Iterator对象称为迭代器,主要用于遍历Collection集合中的元素。
- 实现Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,既可以返回一个迭代器。
- Iterator仅用于遍历集合,Iterator本身不存放对象。
案例演示:
public class IteratorTest {
public static void main(String[] args) {
IteratorTest iteratorTest = new IteratorTest();
iteratorTest.m1();
}
public void m1(){
//1.初始化一个集合list
Collection col = new ArrayList();//父类引用指向子类对象,实现向上转型。方便下面创建迭代器
col.add(new Book("三国演义","罗贯中",10.4));
col.add(new Book("红楼梦","曹雪芹",20.3));
col.add(new Book("小李飞刀","古龙",14.9));
//2.使用迭代器遍历集合
Iterator iterator = col.iterator();//创建迭代器
//快速生成while循环快捷键:itit 显示所有快捷键的快捷键ctrl+j
while (iterator.hasNext()){//hasNext()判断下一个元素是否存在,是则返回true,否则返回false
System.out.println(iterator.next());//iterator.next()1.向下移动一次2.将当前元素的值返回,类型是Object。
/*结果:Book{name='三国演义', auther='罗贯中', price=10.4}
Book{name='红楼梦', auther='曹雪芹', price=20.3}
Book{name='小李飞刀', auther='古龙', price=14.9}
*/
}
//3.当退出while循环后,迭代器Iterator指向最后一个元素,如果下面再去使用另一个Iterator去遍历,就会报错:NoSuchElementException。
//4.如果希望再次遍历,需要重置我们的迭代器。
iterator = col.iterator();//重新创建一次即可
}
}
class Book{
private String name;
private String auther;
private double price;
public Book() {
}
public Book(String name, String auther, double price) {
this.name = name;
this.auther = auther;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuther() {
return auther;
}
public void setAuther(String auther) {
this.auther = auther;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", auther='" + auther + '\'' +
", price=" + price +
'}';
}
}
总结要点:
- 父类引用指向子类对象,实现向上转型。方便下面创建迭代器。
- 快速生成while循环快捷键:itit,显示所有快捷键的快捷键ctrl+j。
- iterator.hasNext()判断下一个元素是否存在,是则返回true,否则返回false。
- iterator.next()1.向下移动一次2.将当前元素的值返回,类型是Object。
- 当退出while循环后,迭代器Iterator指向最后一个元素,如果下面再去使用另一个Iterator去遍历,就会报错:NoSuchElementException。
- 如果希望再次遍历,需要重置我们的迭代器。iterator = col.iterator();//重新创建一次即可
Collection接口遍历元素方式2(for循环增强)
- 增强型for循环,可以替代iterator迭代器,特点:增强for循环就是简化版的iterator,本质一样。只能用于遍历集合或者数组。
- 基本语法:
for (元素类型 元素名:集合名或数组名) {
访问元素
}
- 案例演示:
public class IteratorTest {
public static void main(String[] args) {
IteratorTest iteratorTest = new IteratorTest();
iteratorTest.m2();
}
//使用for-each遍历集合
public void m2(){
//1.初始化一个集合list
Collection col = new ArrayList();//父类引用指向子类对象,实现向上转型。方便下面创建迭代器,也可以用list的引用
col.add(new Book("三国演义","罗贯中",10.4));
col.add(new Book("红楼梦","曹雪芹",20.3));
col.add(new Book("小李飞刀","古龙",14.9));
System.out.println(col);//结果:[Book{name='三国演义', auther='罗贯中', price=10.4}, Book{name='红楼梦', auther='曹雪芹', price=20.3}, Book{name='小李飞刀', auther='古龙', price=14.9}]
//2.使用for-each遍历集合
for (Object obj:col) {
System.out.println(obj);
/*结果:Book{name='三国演义', auther='罗贯中', price=10.4}
Book{name='红楼梦', auther='曹雪芹', price=20.3}
Book{name='小李飞刀', auther='古龙', price=14.9}
*/
}
}
}
class Book{
private String name;
private String auther;
private double price;
public Book() {
}
public Book(String name, String auther, double price) {
this.name = name;
this.auther = auther;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuther() {
return auther;
}
public void setAuther(String auther) {
this.auther = auther;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", auther='" + auther + '\'' +
", price=" + price +
'}';
}
List
-
ArrayList、LinkedList的比较和如何选择:
-
List接口基本介绍:
List接口是Collection接口的子接口。常用实现类有:ArrayList、LinkedList、Vector。
- List集合类中元素有序(即添加顺序和取出顺序一致),且元素可重复。
- List集合中的每个元素都有其对应的顺序索引,即支持索引。
- List容器中的元素都对应一个整数型的序号记载在容器中的位置,可以根据序号存取容器中的元素。
public class ListTest {
public static void main(String[] args) {
List list = new ArrayList();
//1. List集合类中元素有序(即添加顺序和取出顺序一致),且元素可重复。
list.add("tom");
list.add("jack");
list.add("mary");
list.add("tom");
list.add("mary");
System.out.println("List="+list);//结果:List=[tom, jack, mary, tom, mary]
//2. List集合中的每个元素都有其对应的顺序索引,即支持索引。
System.out.println(list.get(1));//结果:jack
}
}
-
List接口的常用方法:
- void add(int index,Object ele);在index处插入ele元素。
- boolean addAll(int index,Collection eles);从index位置开始将eles中的所有元素添加进来。
- Object get(int index);获取指定index位置的元素。
- int indexOf(Object obj);返回obj在集合中首次出现的位置。
- int lastIndexOf(Object obj);返回obj在集合中最后出现的位置。
- Object remove(int index);移除指定index位置的元素,并返回此元素。
- Object set(int index,Object ele);替换指定index位置的元素为ele,被替换的元素必须存在。
- List subList(int fromIndex,int toIndex);返回从fromIndex到toIndex位置(不包含toIndex位置)的子集合。
public class ListTest {
@SuppressWarnings({"all"})
public static void main(String[] args) {
List list = new ArrayList();
list.add("wsn");
list.add(100);
list.add(true);
list.add("wsn");
list.add(100);
list.add("jack");
//1. void add(int index,Object ele);在index处插入ele元素。
list.add(1,"newAdd");//在集合list第2个位置添加一个新的元素"newAdd"。
System.out.println(list);//结果:[wsn, newAdd, 100, true]
//2. boolean addAll(int index,Collection eles);从index位置开始将eles中的所有元素添加进来。
List newList = new ArrayList();
newList.add("newList01");
newList.add("newList02");
newList.add("newList03");
list.addAll(2,newList);//在集合list第3个位置将集合newList的元素全部添加。
System.out.println(list);//结果:[wsn, newAdd, newList01, newList02, newList03, 100, true]
//3. Object get(int index);获取指定index位置的元素。
System.out.println(list.get(4));//获取list集合第5个位置的元素。结果:newList03
//4. int indexOf(Object obj);返回obj在集合中首次出现的位置。
System.out.println(list.indexOf(100));//获取list集合100元素首次出现的位置。结果:5
//5. int lastIndexOf(Object obj);返回obj在集合中最后出现的位置。
System.out.println(list.lastIndexOf("wsn"));//获取list集合"wsn"元素最后出现的位置。结果:7
//6. Object remove(int index);移除指定index位置的元素,并返回此元素。
list.remove(6);//移除集合list第7个位置的元素,也可以直接传入元素名进行移除
System.out.println(list);//结果:[wsn, newAdd, newList01, newList02, newList03, 100, wsn, 100, jack]
//7. Object set(int index,Object ele);修改指定index位置的元素为ele,相当于是替换。
list.set(3,"update");//修改集合list第4个位置元素为“update”
System.out.println(list);//[wsn, newAdd, newList01, update, newList03, 100, wsn, 100, jack]
//8. List subList(int fromIndex,int toIndex);返回从fromIndex到toIndex位置(不包含toIndex位置)的子集合。
System.out.println(list.subList(5, 8));//返回集合list从5到8位置(不包含8位置)的子集合.结果:[100, wsn, 100]
}
}
集合排序练习:
/*
* 使用List的实现类添加三本书,并遍历,打印效果如下
* 名称:xx 价格:xx 作者:xx
* 名称:xx 价格:xx 作者:xx
* 名称:xx 价格:xx 作者:xx
* 要求:1.按价格排序,从低到高(使用冒泡法)。
* 2.要求使用ArrayList,LinkedList,Vector三种集合实现。
* 3.结论:主要说明,只要实现了List接口,那么List的实现类都可以使用List接口中的方法。
* */
public class ListExercise {
public static void main(String[] args) {
new ListExercise().m2();
}
@SuppressWarnings({"all"})
public void m2(){
List list = new ArrayList();
Scanner sc = new Scanner(System.in);
//循环输入书本信息
for (int i = 0; i < 3; i++) {
System.out.println("请输入第"+(i+1)+"本书的名称,价格,作者");
Booknew booknew = new Booknew(sc.next(), sc.nextDouble(), sc.next());
list.add(booknew);
}
//for-each遍历(未排序之前)
System.out.println("============= 未排序之前 ==============");
for (Object obj:list) {
System.out.println(obj);
}
ListExercise listExercise = new ListExercise();
listExercise.sort(list);//调用排序方法
System.out.println("============= 排序之后 ==============");
//for-each遍历(排序之后)
for (Object obj:list) {
System.out.println(obj);
}
sc.close();//关闭流
}
//集合排序方法
public void sort(List list){//将list集合传入
int listSize = list.size();//将list.size()提出,提高循环效率。
//冒泡排序
for (int i = 0; i < listSize-1; i++) {
for (int j = 0; j <listSize-1-i ; j++) {
Booknew b1 = (Booknew)list.get(j);//获取list的当前元素并向下转型,就可以获取到价格price去比较
Booknew b2 = (Booknew)list.get(j+1);//获取list的当前元素并向下转型,就可以获取到价格price去比较
if (b1.getPrice()> b2.getPrice()){//比较大小
//如果true,就用list.set(int index,Object ele)交换,
list.set(j,b2);
list.set(j+1,b1);
}
}
}
}
}
class Booknew{
private String name;
private double price;
private String auther;
public Booknew(String name, double price, String auther) {
this.name = name;
this.price = price;
this.auther = auther;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getAuther() {
return auther;
}
public void setAuther(String auther) {
this.auther = auther;
}
@Override
public String toString() {
return "名称:" + name +"\t\t\t"+ "价格:" + price+"\t\t\t"+ "作者:" + auther;
}
}
ArrayList
-
注意事项:
- ArrayList可以添加任意元素(元素可以重复),包括null。
- ArrayList是由数组来实现数据的存储的。
- ArrayList基本等同于Vector,除了ArrayList是线程不安全的(执行效率高),在多线程的情况下,不建议用ArrayList。
-
ArrayList底层结构和源码分析:
-
ArrayList中维护了一个Object类型的数组elementDate。
transient Object[] elementData;//transient 表示瞬间,短暂。表示该属性不会被序列化。
-
当创建ArrayList对象时,如果使用的是无参构造,则初始的elementData容量为0,第一次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍。
-
如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要再次扩容,则直接扩容elementData为1.5倍。
-
LinkedList
-
基本介绍:
- LinkedList实现了双向链表和双端队列的特点。
- 可以添加任意元素(元素可以重复),包括null。
- 线程不安全,没有实现同步。
-
LinkedList底层操作机制:
- LinkedList底层维护了一个双向链表。
- LinkedList中维护了两个属性,first和last分别指向首节点和尾节点。
- 每个节点(Node对象),里面又维护了prev,next,item三个属性,其中通过prev指向前一个,通过next指向后一个介蒂安,实现双向链表。
- 所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高。
Vector
-
Vector基本介绍:
-
Vector类的定义说明.
-
Vector底层也是一个数组对象,protected Object[] elementData;
-
在开发中,需要线程同步安全时,考虑使用Vector。
-
Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronized。
//Vector类get()方法源码 public synchronized E get(int index) { if (index >= elementCount) throw new ArrayIndexOutOfBoundsException(index); return elementData(index); }
-
Set
-
Set接口基本介绍:
- 无序(添加和取出的顺序不一致),没有索引。
- 不允许重复元素,所以最多包含一个null。
-
Set接口的常用方法:
和List接口一样,Set接口也是Collection的子接口,因此,常用的方法和List一样。
-
Set接口的遍历方式:
- 可以使用迭代器。
- 增强for循环。
- 不能使用索引(也就普通for循环)的方式获取。
public class HashSetTest {
public static void main(String[] args) {
new HashSetTest().m1();
}
/*
* HashSet遍历
* 1.重复的元素不会存入,顺序也是无序的。
* 2.虽然是无序的,但位置是固定的。
* */
@SuppressWarnings({"all"})
public void m1(){
Set hashSet = new HashSet();
hashSet.add("jhon");
hashSet.add("jack");
hashSet.add("mary");
hashSet.add("jhon");
hashSet.add("null");
hashSet.add("null");
//重复的元素不会存入,顺序也是无序的
System.out.println(hashSet);//结果:[null, mary, jhon, jack]
//增强遍历
for (Object obj:hashSet) {
System.out.println(obj);
}
//迭代器遍历
Iterator iterator = hashSet.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
HashSet
-
HashSet介绍:
- HashSet实现了Set接口。
- 可以存放null值,但只能是一个。
- 不能有重复的元素,在前面Set讲过。
- Set接口没有get方法。
- HashSet实际上是HashMap,源码如下:
Pubilc HashSet(){
map = new HashMap<>();
}
- 案例演示:
//1.在执行add方法后,会返回一个boolean值
//2.如果添加成功返回true,否则返回false
System.out.println(hashSet.add("null"));//结果:true
System.out.println(hashSet.add("123"));//结果:true
System.out.println(hashSet.add("345"));//结果:true
System.out.println(hashSet.add("null"));//结果:false
public class HashSetTest {
public static void main(String[] args) {
new HashSetTest().m1();
}
/*
* 从1.和2.来看结论似乎是冲突的,为什么Duck两个不一样对象能添加成功,而String两个不一样对象为什么不能添加,这个问题具体要看底层add方法具体是怎么添加的,先知道结论,这个问题以后再说。
* */
@SuppressWarnings({"all"})
public void m1(){
Set hashSet = new HashSet();
System.out.println(hashSet.add("jhon"));//结果:true
System.out.println(hashSet.add("jack"));//结果:true
System.out.println(hashSet.add("jhon"));//结果:false
//1.当用Duck类实例化两个新的对象用同的内容添加,结果添加成功
System.out.println(hashSet.add(new Duck("tom")));//结果:true
System.out.println(hashSet.add(new Duck("tom")));//结果:true
//2.当用String类实例化两个对象用同的内容添加,结果不能添加
System.out.println(hashSet.add(new String("mary")));//结果:true
System.out.println(hashSet.add(new String("mary")));//结果:false
}
}
class Duck{
private String name;
public Duck(String name) {
this.name = name;
}
@Override
public String toString() {
return name ;
}
}
- 案例演示:
/*
* 练习:
* 1.创建员工类Employee,里面有两个属性name,age
* 2.用HashSet添加三个员工的信息,实现两个员工当名字和年龄相同,证明是同一员工,则不能添加。
* 思路:因为用对象去添加员工信息,每个对象的哈希值不同,所以即使两个员工name,age相同也能添加成功,
* 所以要解决这个问题,我们需要在员工类中重写equals和hashcode的方法,实现当两个员工name和age相同时返回同一哈希值。
*
* */
@SuppressWarnings({"all"})
public class HashSetExercise {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
hashSet.add(new Employee("aaa",111));
hashSet.add(new Employee("bbb",222));
hashSet.add(new Employee("ccc",333));
System.out.println("===================== 添加前员工信息 =========================");
System.out.println(hashSet);
Scanner sc = new Scanner(System.in);
System.out.println("输入一个员工信息姓名和年龄");
Employee employee = new Employee(sc.next(), sc.nextInt());
if(hashSet.add(employee)){
System.out.println("添加成功");
}else {
System.out.println("添加失败");
}
System.out.println("===================== 添加后前员工信息 =========================");
System.out.println(hashSet);
}
}
@SuppressWarnings({"all"})
class Employee{
private String name;
private int 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;
}
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return
"name=" + name+"\t" +"age=" + age ;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age && Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
TreeSet
留个坑,暂无内容。
Map
-
Map接口特点:
- Map与Collection并列存在,用于保存具有映射关系的数据:key-value。
- Map中的key和value可以是任何引用类型的数据,会封装到HashMap¥Node对象中。
- Map中的Key不允许重复。
- Map中的Value可以重复。
- Map中的key可以为null,value也可以为null,注意key为null只能有一个,value为null可以有多个。
- 常用String类作为Map的key
- key和value之间存在单向一对一的关系,即通过指定的key总能找到对应的value。
-
Map接口和常用方法:
- put(Object key, Object value);添加。
- remove(Object key);根据键删除映射关系。
- get(Object key);根据键获取值。
- size();获取元素个数。
- isEmpty();判断个数是否为0。
- clear();清除
- containsKey(Object key);查找键是否存在。
@SuppressWarnings({"all"})
public class MapTest {
public static void main(String[] args) {
new MapTest().m1();
}
public void m1(){
Map map = new HashMap();
Phone phone = new Phone();
Phone meizu = new Phone("魅族", 998);
Phone pinguo = new Phone("苹果", 5999.00);
Phone xiaomi = new Phone("小米", 2399.00);
//1. put(Object key, Object value);添加。
map.put(meizu.getName(),meizu.getPrice());
map.put(pinguo.getName(),pinguo.getPrice());
map.put(xiaomi.getName(),xiaomi.getPrice());
System.out.println(map);//结果:{苹果=5999.0, 魅族=998.0, 小米=2399.0}
//2. remove(Object key);根据键删除映射关系。
map.remove(pinguo.getName());
System.out.println(map);//结果:{魅族=998.0, 小米=2399.0}
//3. get(Object key);根据键获取值。
System.out.println(map.get(xiaomi.getName()));//结果:2399.0
//4. size();获取元素个数。
System.out.println(map.size());//结果:2
//5. isEmpty();判断个数是否为0。
System.out.println(map.isEmpty());//结果:false
//6. containsKey(Object key);查找键是否存在。
System.out.println(map.containsKey(meizu.getName()));//结果:true
//7. clear();清除
map.clear();
System.out.println(map);//结果:{}
}
}
class Phone{
private String name;
private double price;
public Phone() {
}
public Phone(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
if (this.name == null) {
return "price=" + price;
}
if (this.price == 0) {
return "name=" + name;
}
return "";
}
-
Map的三种遍历方式:
@SuppressWarnings({"all"})
public class MapTraverse {
public static void main(String[] args) {
Map map = new HashMap();
map.put("1","朱新宇");
map.put("3","王少楠");
map.put("2","陈廷伟");
map.put("4","张志涛");
map.put("5","付晓宇");
map.put("6","曾磊");
map.put("7","覃家黎");
map.put("8","谈嘻嘻");
new MapTraverse().test(map);
}
//1.用迭代器遍历Map
public void MapTraverse01(Map map){
Set set = map.keySet();//获取所有的键值,放入集合
Iterator iterator = set.iterator();//用存有键值的集合创建迭代器
while (iterator.hasNext()) {//这里的hasNext()和next()实际上指向的就是键值
Object key = iterator.next();//将当前指向的键值创建成一个对象
Object value = map.get(key);//用map的get方法传入当前指向的键值对象
System.out.println(value);
}
}
//2.用for-each遍历Map
public void MapTraverse02(Map map){
Set set = map.keySet();
for (Object obj:set) {
System.out.println(obj+":"+map.get(obj));
}
}
//3.用entrySet遍历Map
public void MapTraverse03(Map map){
Set entrySet = map.entrySet();
for (Object entry:entrySet) {
Map.Entry e = (Map.Entry) entry;
Object key = e.getKey();
Object value = e.getValue();
System.out.println(key+":"+value);
}
}
public void test(Map map){
new MapTraverse().MapTraverse01(map);
System.out.println("================================================");
new MapTraverse().MapTraverse02(map);
System.out.println("================================================");
new MapTraverse().MapTraverse03(map);
}
}
HashMap
-
HashMap小结:
- HashMap是Map接口中使用频率最高的。
- key不能重复,但是值可以重复,允许使用null键和null值。
- 如果添加相同的key,那么就会覆盖原来的key-val,等同于修改。
- 与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式存储的。
- HashMap没有实现同步,因此线程是不安全的。
HashTable
-
HashTable介绍:
- 存放的元素是键值对。
- HashTable的键和值都不能为null。
- HashTable使用方法基本上和HashMap一样。
- HashTable是线程安全的,HashMap是线程不安全的。
Properties
-
Properties介绍:
- Properties类继承了HashTable类并实现了Map接口,也是一种键值对形式来保存数据。
- 他的使用特点和HashTable类似。
- Properties还可以用于从xxx.properties文件种,加载数据到Properties类对象,并进行读取和修改。
总结:
-
在开发中选择什么样的集合实现类,取决于业务操作的特点,然后根据集合实现类的特性进行选择:
-
先判断存储的类型(一组对象[单列集合]或一组键值对[双列集合])。
-
一组对象[单列集合]:
-
允许重复元素:List
- 增删多:选LinkedList(底层维护了一个双向链表)。
- 改查多:选ArrayList(底层维护了Object类型的可变数组)。
-
不允许重复元素:Set
- 无序:HashSet(底层是HashMap,维护了一个哈希表[即数组+链表+红黑树])。
- 排序:TreeSet。
- 插入和取出顺序一致:选LinkedHashSet(维护数组+双向链表),
-
-
一组键值对[双列集合]:Map
- 键无序:HashMap(底层是哈希表。jdk7:数组+链表,jdk8:数组+链表+红黑树)。
- 键排序:TreeMap.
- 键插入和取出顺序一致:LinkedHashMap。
- 读取文件:properties。
-