第一部分:概述
一、集合类
1、面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象进行操作,就需要对对象进行存储,集合类就是存储对象最常用的一种方式。
2、集合与数组的区别:
数组虽然也可以存储对象,但长度是固定的,且数组不可能进行增删操作;
集合的长度是可变的,数组可以存储基本数据类型,集合只能存储对象。
3、集合类的特点:
数据多了用对象存储,对象多了用集合存储。集合只能存储对象,且集合的长度是可变的;集合可以存储不同类型的对象。
二、集合框架
容器分很多种,就有了很多共性,经过不断的向上抽取,慢慢就产生了体系 ---- 集合框架。每个容器对数据的存储方式都不同,这个存数方式称为数据结构。
第二部分:Collction集合(java.util.Collection)
Collection是集合框架的一个顶层接口,它是单列集合,该接口下有两个子接口,List与Set。
|---- Collection<E>
一、Collection集合常用方法|---- List<E>
|---- Set<E>
Collection接口中的方法是该体系下的共性方法,常用方法如下:
1、添加元素
boolean add(E e) 添加元素
boolean addAll(Collection<? extends E> c) 将Collection集合中的所有元素都添加到该集合中
2、获取个数
int size() 获取集合中元素的个数
3、删除元素
boolean remove(Object obj) 移除集合中的指定元素
boolean removeAll(Collection<? extends E> c) 移除该集合与Collection集合的交集
void clear() 清空集合
4、判断元素
boolean isEmpty() 判断集合时候为空
boolean contains(Object obj) 判断集合是否包含指定元素
boolean containsAll(Collection<? extends E> c) 判断集合中是否包含Collection集合中的所有元素
boolean retainsAll(Collection<? extends E> c) 获取该集合与Collection集合中的交集
5、获取迭代器
Iterator<E> iterator() 获取迭代器,用于取出集合中的元素
二、迭代器的由来
1、由来
每个容器都有自己的存储和取出元素的方法,因为每个容器的数据结构不一样,所以存储和取出的动作也不一样。
对于取出这个动作(判断是否有元素,再取),不足以用一个方法来描述,它需要用多个功能来体现,所以这多个功能定义在类中。因为取出的元素都在集合中,取出这个类就定义在了集合的内部,若想直接操作元素,定义内部类最为方便。
而每一个容器的数据结构不同,所以取出动作的细节也不一样,但是都有判断、抽取的共性内容,那么可以将共性进行抽取,形成一个接口:Iterator。Collection集合子类中的iterator()方法返回的是Iterator的子类对象,
图例:
2、迭代器中的方法
boolean hasNext() 如果仍有元素可以迭代,则返回 true
E next() 返回迭代的下一个元素
void remove() 从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)
示例代码:
//导入util包中的ArrayList类与Iterator import java.util.ArrayList; import java.util.Iterator; public class CollectionDemo { public static void main(String[] args){ //创建Collection集合的子类对象 ArrayList<String> al = new ArrayList<String>(); //向集合中添加元素 al.add("java 01"); al.add("java 02"); al.add("java 03"); al.add("java 07"); //获取迭代器 Iterator<String> it = al.iterator(); while(it.hasNext()){ //打印集合的元素 sop(it.next()); } } public static void sop(Object obj){ System.out.println(obj); } }
第三部分:List集合
|---- Collection<E>
|---- List<E> 子接口,该集合中的元素是有序的,元素可以重复,该集合有索引
一、List集合中特有的方法
凡是可以操作角标的方法都是该集合中的特有方法。
1、增
void add(int index,E element) 在列表的指定位置插入指定元素
boolean addAll(int index,Collection<? extends E> c)
添加指定 collection 中的所有元素到此列表的结尾,顺序是指定 collection 的迭代器返回这些元素的顺序(可选操作)。
2、删
E remove(int index) 移除指定位置上的元素
3、改
E set(int index,E element) 用指定元素替换列表中指定位置的元素
4、查
E get(int index) 返回列表中指定位置的元素
List subList(int fromIndex, int toIndex) 返回列表中指定的 fromIndex(包括 )和toIndex(不包括)之间的集合
int indexOf(Object obj) 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1
int lastIndexOf(Object obj) 返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1
ListIterator<E> listIterator() 返回此列表元素的列表迭代器
二、列表迭代器
示例代码:
运行结果:package demo; import java.util.ArrayList; import java.util.Iterator; public class ListIteratorDemo{ public static void main(String[] args){ //定义集合 ArrayList<String> al = new ArrayList<String>(); al.add("abc1"); al.add("abc2"); al.add("abc3"); //获取迭代器 Iterator<String> it = al.iterator(); while(it.hasNext()){ //在迭代的过程中使用集合的方法对集合中的元素进行增删操作 String str = it.next(); if(str=="abc1"){ al.add("abc4"); } } } }
发生了并发修改异常(ConcurrentModificationException),因为在对集合使用迭代器中的方法进行操作时,又采用了集合中的增加元素的方法,即对同一组元素进行了多种同时并发操作,发生了异常。可是Iterator的方法是有限的,只能对元素进行判断,取出和删除,如果想要其他操作,则需要使用ListIterator。
List集合特有的迭代器:ListIterator,是Iterator的子接口,其提供了以下方法:
void add(E e) 将指定的元素插入列表(可选操作)
boolean hasNext() 以正向遍历列表时,如果列表迭代器有多个元素,则返回 true
boolean hasPrevious() 如果以逆向遍历列表,列表迭代器有多个元素,则返回 true
E next() 返回列表中的下一个元素
int nextIndex() 返回对 next 的后续调用所返回元素的索引
E previous() 返回列表中的前一个元素
int previousIndex() 返回对 previous 的后续调用所返回元素的索引
void remove() 从列表中移除由 next 或 previous 返回的最后一个元素
void set(E e) 用指定元素替换 next 或 previous 返回的最后一个元素
示例代码:
运行结果:import java.util.ArrayList; import java.util.ListIterator; public class ListIteratorDemo{ public static void main(String[] args){ ArrayList<String> al = new ArrayList<String>(); al.add("abc1"); al.add("abc2"); al.add("abc3"); //获取列表迭代器 ListIterator<String> it = al.listIterator(); while(it.hasNext()){ //在迭代的过程中使用迭代器的方法对集合中的元素进行增删操作 String str = it.next(); if(str=="abc1"){ it.add("abc4"); } } System.out.println(al); } }
三、List集合的子类
|---- List<E> 子接口
|---- ArrayList<E>::底层数据结构:数据数据结构
|---- LinkedList<E>:底层数据结构:链表数据结构
|---- Vector<E>:底层数据结构:数组数据结构
1、ArrayList与LinkedList
ArrayList:查询及修改很快,增删稍慢。元素不多,有增删,也有查询操作时,用ArrayList。
LinkedList:查询很慢,增删很快。当增删特别多时,用LinkedList。
2、ArrayList与Vector
ArrayList:线程不同步,效率高;默认长度为10,长度超过时以50%延长。(JDK1.2出现)
Vector:线程同步,效率低;默认长度为10,长度超过时以100%延长。被ArrayList取代。(JDK1.0出现)
3、Vector集合及枚举
Vector集合有一个特有的取出方式,即枚举。通过vector中的以下方法获取。
Enumeration<E> elements() 返回此向量的组件的枚举。
Enumeration接口中有自己的取出方法
boolean hasMoreElements() 测试此枚举是否包含更多的元素。
E nextElement() 如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。
示例代码:
import java.util.Enumeration; import java.util.Vector; public class VectorDemo { public static void main(String[] args) { //创建Vector集合 Vector<String> v = new Vector<String>(); //添加元素 v.add("java01"); v.add("java02"); v.add("java03"); //采用枚举取出元素 Enumeration<String> en = v.elements(); while(en.hasMoreElements()) { System.out.println(en.nextElement()); } } }
4、LinkedList集合
LinkedList集合中特有方法:
void addFirst(E e) 将元素添加进队列的头
void addLast(E e) 将元素添加进队列的尾
E getFirst() 获取元素,但不删除元素(若集合中无该元素,则抛出异常)
E getLast()
E removeFirst() 获取元素,但删除元素
E removeLast()
1.6版本出现了替代方法:
E pollFirst() 获取并删除元素(若元素不存在,则返回null)
E pollLast()
E peckFirst() 获取元素但不删除元素
E peckLast()
boolean offerFirst() 添加元素
boolean offerLast()
使用LinkedList集合可以实现队列结构和堆栈结构:
队列结构:先进先出,如同一个水管
堆栈结构:先进后出,如果一个杯子
运行结果:package day.day4; /* * 将LinkedList封装成一个新的容器,实现队列结构与堆栈结构 * * 队列结构:先进先出 * 堆栈结构:先进后出 * * 由于LinkedList中没有这种方法,因此自己封装好,供项目使用(基于LinkedList) * * 向这种封装方式很常见,虽然直接可以用LinkList可以完成,但是想做成和项目相关的容器,起一些和项目相关的名称 * 这种开发方式很常见 */ import java.util.*; public class MyDuiLie { public static void main(String[] args){ //队列结构 DuiLie dl = new DuiLie(); dl.myAdd("java01"); dl.myAdd("java02"); dl.myAdd("java03"); sop("队列结构"); while(!dl.isNull()){ sop(dl.myRemove()); } //堆栈结构 DuiZhan dz = new DuiZhan(); dz.myAdd("java01"); dz.myAdd("java02"); dz.myAdd("java03"); sop("堆栈结构"); while(!dz.isNull()){ sop(dz.myRemove()); } } public static void sop(Object obj){ System.out.println(obj); } } //基于LinkList集合定义新的集合实现队列结构 class DuiLie{ LinkedList link; DuiLie(){ link = new LinkedList(); } public boolean isNull(){ return link.isEmpty(); } //存入与删除动作一致 public void myAdd(Object obj){ link.addLast(obj); } public Object myRemove(){ return link.removeFirst(); } } //基于LinkList集合定义新的集合实现堆栈结构 class DuiZhan{ LinkedList link; DuiZhan(){ link = new LinkedList(); } public boolean isNull(){ return link.isEmpty(); } //存入与删除动作相反 public void myAdd(Object obj){ link.addFirst(obj); } public Object myRemove(){ return link.removeFirst(); } }
5、List集合练习
示例代码:
import java.util.ArrayList; import java.util.Iterator; import java.util.List; /* * 需求:去除List集合中的重复元素。 * 思路: * 1、定义一个新集合,遍历旧集合 * 2、遍历旧集合过程中判断新集合中是否包含该元素,不包含则添加 * 3、返回新集合 */ public class ListDemo { public static void main(String[] args){ //定义一个ArrayList集合 ArrayList<Person> al = new ArrayList<Person>(); //添加元素(有重复的) al.add(new Person("zhangsan01",20)); al.add(new Person("zhangsan02",23)); al.add(new Person("zhangsan01",20)); al.add(new Person("zhangsan03",25)); print(al); al = single(al); print(al); //移除元素 al.remove(new Person("zhangsan03",25)); } //实现去重复元素的功能 public static ArrayList<Person> single(ArrayList<Person> al){ //定义新集合 ArrayList<Person> newAl = new ArrayList<Person>(); //对旧集合进行迭代 Iterator<Person> it = al.iterator(); while(it.hasNext()){ Person p = it.next(); //判断新集合中是否包含该元素,不包含,则添加 if(!newAl.contains(p)){ newAl.add(p); } } //返回新集合 return newAl; } //对集合进行打印 public static void print(List<Person> list){ Iterator<Person> it = list.iterator(); while(it.hasNext()){ System.out.println(it.next()); } } } //对Person进行描述 class Person{ private String name;//为节约空间,未对私有属性进行set与get private int age; Person(String name,int age){ this.name = name; this.age = age; } //覆盖Object类中的equals方法 public boolean equals(Object obj){ if(!(obj instanceof Person)){ return false; } Person p = (Person)obj; System.out.println(this.name+"..equals.."+p.name); return this.name.equals(p.name) && this.age==p.age; } public String toString(){ return this.name +"-"+ this.age; } }
运行结果:
由结果可以看出:
List集合判断元素是否相同(contains方法)以及删除元素(remove方法),依赖的是元素的equals方法。List集合的contains方法与remove方法在运行时会自动调用对象的equals方法,若要判断元素的内容是否相等要先覆盖Object类的equals方法。
第四部分:Set集合
|---- Collection<E>
|---- Set<E> 子接口。 元素是无序的(相对存入与取出),元素不可以重复
|---- HashSet<E> 线程不同步,效率高。哈希表
|---- TreeSet<E> 线程不同步,效率高。二叉树
一、HashSet集合
1、数据结构
HashSet集合的底层数据结构是哈希(值)表。哈希值是JVM算出来的内存地址值,每一个对象都有自己的哈希值。
2、元素唯一性
对于HashSet集合,当数据进内存时,会先判断元素的Hash值是是否相等(hashCode方法)。若哈希值不等,则直接将元素存入集合中;若哈希值相等,则会接着判断两个对象是否相等(equals方法),不等才存入集合中。
因此,以后描述事物时,若该事物的对象需要存到集合中,则要覆盖int hashCode()方法与boolean equals(Object obj)方法。
示例代码:
/* 需求:往HashSet集合中存入学生对象。若学生的姓名和年纪相同则视为同一对象 */ import java.util.HashSet; public class HashSetDemo { public static void main(String[] args){ //定义HashSet集合 HashSet<Person> hs = new HashSet<Person>(); //存入元素(有重复) hs.add(new Person("wangwu1",20)); hs.add(new Person("wangwu2",22)); hs.add(new Person("wangwu2",22)); hs.add(new Person("wangwu3",24)); sop(hs); } public static void sop(Object obj){ System.out.println(obj); } } class Person{ private String name;//为节约空间,未对私有属性进行set与get private int age; Person(String name,int age){ this.name = name; this.age = age; } //覆盖hashCode方法, public int hashCode(){ return this.name.hashCode()+this.age*37; } //覆盖equals方法 public boolean equals(Object obj){ if(!(obj instanceof Person)){ return false; } Person p = (Person)obj; return this.name.equals(p.name) && this.age==p.age;//注意判断字符串是否相等用的是equals方法,不是== } public String toString(){ return this.name +":"+ this.age; } }
运行结果:
二、TreeSet集合
1、数据结构
TreeSet集合底层数据结构是二叉树,又名红黑数。TreeSet集合中的元素是有序的。
2、元素唯一性
1)元素自身基本比较性
让元素自身具备比较性,按以下步骤执行:
这种方式也成为元素的自然顺序或默认顺序。(a)元素所对应的类需要实现 Comparable 接口
(b)覆盖 int compareTo(E e) 方法
示例代码:
运行结果:import java.util.TreeSet; import java.util.Iterator; /* * 需求:往TreeSet集合中存入Person对象,并按年龄进行排序 */ public class TreeSetDemo { public static void main(String[] args){ //第一种方式:元素自身具备比较性 TreeSet<Person> ts = new TreeSet<Person>(); ts.add(new Person("zhangsan01",20)); ts.add(new Person("zhangsan02",24)); ts.add(new Person("zhangsan01",22)); ts.add(new Person("zhangsan03",23)); ts.add(new Person("zhangsan07",23)); printColl(ts); } public static void printColl(TreeSet<Person> ts){ Iterator<Person> it = ts.iterator(); while(it.hasNext()){ System.out.println(it.next()); } } } //定义Person类实现ComParable接口 class Person implements Comparable<Person>{ private String name;//为节约空间,未对私有属性进行set与get private int age; Person(String name,int age){ this.name = name; this.age = age; } //覆盖接口中的compareTo方法 public int compareTo(Person p){ if(this.age>p.age) return 1; //当age相同时判断name是否相同 if(this.age==p.age) return this.name.compareTo(p.name); return -1; } public String toString(){ return name+"-"+age; } }
图解:
当二叉树中元素较多时,会从折中值开始查找。(add方法底层调用了compareTo方法,判断元素是否相等,这也是add方法返回值类型为boolean的原因)
2)集合自身具备比较性
当元素自身不具备比较性,或者自身具备的比较性不是所需要的,这时就需要让结合自身具备比较性。步骤:
(a)定义比较器实现 Comparator 接口
(b)覆盖 int compare(E o1,E o2) 方法
(c)将比较器对象作为参数传递给TreeSet集合的构造函数
示例代码:
/* * 需求:定义比较器,按Person的name进行排序 */ import java.util.Comparator; import java.util.Iterator; import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args){ //定义集合,传入比较器对象,让集合自身具备比较性 TreeSet<Person> tr = new TreeSet<Person>(new MyComparator()); //存入元素(有重复) tr.add(new Person("zhangsan01",20)); tr.add(new Person("zhangsan02",24)); tr.add(new Person("zhangsan01",22)); tr.add(new Person("zhangsan03",23)); tr.add(new Person("zhangsan07",23)); printColl(tr); } public static void printColl(TreeSet<Person> ts){ Iterator<Person> it = ts.iterator(); while(it.hasNext()){ System.out.println(it.next()); } } } //描述学生 class Person{ private String name; private int age; Person(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; } public String toString(){ return name+"-"+age; } } //定义比较器实现Comparator接口 class MyComparator implements Comparator<Person>{ //覆盖compare方法 public int compare(Person p1,Person p2){ //主要条件:学生的名字 int num = p1.getName().compareTo(p2.getName()); //次要条件:学生的年龄 if(num==0){ return new Integer(p1.getAge()).compareTo(new Integer(p2.getAge())); } return num; } }
运行结果:
注意:
1、在使用TreeSet集合时,当主要条件相同时,一定要判断次要条件。
2、以后在描述事物时,需要覆盖hashCode()与equals方法;实现Comparable接口并覆盖compareTo方法让其具备比较性。
第五部分:泛型
一、概述
泛型是JDK1.5版本出现的新特性,用于解决安全问题(即限制所操作的类型),是一个类型安全机制。如:
TreeSet al = new TreeSet();
al.add(new Person("lisi",24));
al.add("java01");上述代码在编译时不会报错,在运行时(会调用compareTo方法)发生类型转换异常(ClassCastException)。加入泛型后:
TreeSet<Person> al = new TreeSet<Person>();
al.add(new Person("lisi",24));
al.add("java01");
1、将运行时产生的问题ClassCastException转移到编译时期,方便程序员解决问题,让运行问题减少、安全。
2、不用再做类型强制转换动作。(Object类中的equals方法除外,因为该方法没有定义泛型)
二、泛型定义
1、基本格式
通过<>来定义要操作的引用数据类型。泛型在集合框架中很常见,只要见到<>,就要定义泛型。
2、泛型类
1)何时定义泛型类
当类中要操作的引用数据类型不确定时,早期定义Object来完成扩展,现在定义泛型来完成扩展。
2)示例代码
3)泛型类的优缺点/* 需求:演示泛型类 */ //要操作的数据类型不确定,定义泛型来完成扩展 class Tools<QQ> { private QQ q; public void set(QQ q) { this.q = q; } public QQ get() { return q; } } class Demo { public static void main(String[] args) { //在创建对象时指定要操作的引用数据类型 Tools<String> tl = new Tools<String>(); tl.set("abc"); } }
优点:泛型类定义的泛型,在整个类中有效。
缺点:QQ类型只要一确定,里面的类型就确定了。(对象一建立,要操作的类型就确定了)
3、泛型方法
为了让不同的方法可以操作不同类型,且类型不确定,可以将泛型定义在方法上。
泛型方法定义格式:泛型定义在返回值的前面,修饰符的后面。
示例代码:
注意:/* 需求:泛型方法演示 */ class Tools { //泛型方法 public <T> void show(T t) { System.out.println(t); } public <Q> void print(Q q) { System.out.println(q); } } class Demo { public static void main(String[] args) { Tools t = new Tools(); //调用方法时指定要操作的数据类型 d.show("abc"); d.print(new Integer(56)); } }
1、泛型类中可以再定义泛型方法。泛型类控制未定义泛型方法的成员,泛型方法控制该方法中的局部变量。
2、静态方法不可以访问类上定义的泛型。如果静态方法要操作的类型不确定,可以将泛型定义在方法上。
4、泛型接口
/* * 需求:演示泛型接口 */ //泛型定义在接口上 interface Inter<T> { public abstract void show(T t); } //子类实现时指定要操作的数据类型 class Demo implements Inter<String> { public void show(String str) { System.out.println(str); } } //子类实现时要操作的数据类型不确定,定义泛型类实现 class Test<T> implements Inter<T> { public void show(T t) { System.out.println(t); } }
三、泛型限定
1、基本符号
? 通配符,也可以理解为占位符
? extends E 可以接收E类型或者E的子类型,上限限定
? super E 可以接收E类型或者E的父类型,下线限定
2、用法
当对象的类型不确定时,用通配符“?”表示,但不能对其类型下的数据进行具体操作,因为?表示不确定类型。
示例代码:
TreeSet(Collection<? extends E> c) 上限限定import java.util.Iterator; import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args){ TreeSet<String> ts1 = new TreeSet<String>(); ts1.add("dian01"); ts1.add("dian04"); ts1.add("dian02"); //操作String类型 printColl(ts1); TreeSet<Integer> ts2 = new TreeSet<Integer>(); ts2.add(3); ts2.add(5); ts2.add(2); //操作Integer类型 printColl(ts2); } /* * 定义功能,对集合中的数据进行打印 * 要操作的TreeSet集合的类型不确定,使用"?"完成扩展 * 不能在方法中对数据进行String或Integer的特有方法进行操作,因为类型不确定 */ public static void printColl(TreeSet<?> ts){ Iterator<?> it = ts.iterator(); while(it.hasNext()){ System.out.println(it.next()); } } }
TreeSet(Comparator<? super E> comparator) 下限限定(以后定义比较器时,泛型限定为父类的(super E),在定义集合时,可以往构造方法传入父类的比较器,这样就大大提高了程序的扩展性。如:/* 泛型限定演示 |--- Person(父类) |--- Student(子类) */ //定义父类比较器 public class MyComparator implements Comparator<Person>{ public int compare(Person p1,Person p2){ int num = p1.getName().compareTo(p2.getName()); if(num==0){ return new Integer(p1.getAge()).compareTo(new Integer(p2.getAge())); } return num; } } class Demo{ public static void main(String[] args){ TreeSet<Student> ts = new TreeSet<Student>(new MyComparator); ts.add(new Student("wangwu03",24); ts.add(new Student("wangwu02",20); ts.add(new Student("wangwu01",26); } }
第六部分:Map集合
一、概述
|---- Map<K,V> 接口。 K - 此映射所维护的键的类型;V - 映射值的类型
|---- HashMap<K,V>
|---- HashTable<K,V>
|---- Properties 与IO相结合的集合(无泛型)
|---- TreeMap<K,V>
Map集合时双列集合,里面存放的是键值对;一个键只能对应一个值,即要保证键的唯一性。
Collection集合是单例集合。
1、HashTable
HashTable底层是哈希表的数据结构,该集合中不可以存入null键null值;且该集合是同步的,效率低;用作键的对象必须复写hashCode方法与equals方法。(JDK1.0出现)
2、HashMap
HashMap底层也是哈希表的数据结构,该集合可以存入null键null值;该集合不同步,效率高。(JDK1.2出现)
3、TreeMap
底层数据结构是二叉树;线程不同步;可以用于给Map集合中的键进行排序,同样也有两种方式对元素进行比较(自然顺序,比较器)。
4、Map与Set的关系
Set集合底层使用Map集合,只是Set是单例集合,Map是双列集合。
5、Map.Entry
Map.Entry是一个接口,表示键值对的映射关系。该接口定义在Map接口的内部,是一个内部接口,而且是静态的。该接口中有以下方法:
K getKey() 返回与此项对应的键
V getValue() 返回与此项对应的值
二、Map集合常用方法
1、增
V put(K key,V value) 将指定的值与此映射中的指定键关联(后添加的值会覆盖原来的值,并返回被覆盖的值)
void putAll((Map<? extends K,? extends V> m) 从指定映射中将所有映射关系复制到此映射中
2、删
void clear() 清空集合
V remove(Object key) 如果存在一个键的映射关系,则将其从此映射中移除(如果没有 key 的映射关系,则返回null)
3、判断(没有isEmpty方法)
boolean containsKey(Object key) 是否包含指定的键
boolean containsValue(Object value) 是否包含指定的值
4、获取
V get(Object key) 获取指定键上的值,不存在则返回null。(可用于判断一个键是否存在)
int size() 获取集合中键值映射关系数
Collection<V> value() 返回map集合中值的Collection集合
Set<K> keySet() 返回集合中键的Set集合
Set<Map.Entry<K,V>> entrySet() 返回集合中映射关系的Set集合
三、示例代码
1、通过Set集合获取集合中的元素
运行结果:/* 需求:取出集合中的元素 有两种方法 keySet entrySet */ import java.util.*; public class MapDemo { public static void main(String[] args){ //定义HashMap集合 Map<String,String> map = new HashMap<String,String>(); //存入元素 map.put("01", "guiyang"); map.put("03", "zunyi"); map.put("04", "zhengan"); map.put("02", "miaotang"); //Map集合的第一种取出方式(keySet)获取键的Map集合 Set<String> set = map.keySet(); //获取Set集合中的迭代器 Iterator<String> it = set.iterator(); //迭代键的Set集合 while(it.hasNext()){ //获取每一个键 String key = it.next(); //通过Map集合的get方法获取键删对象的值 System.out.println(key+"="+map.get(key)); } //第二种取出方法(entrySet)获取映射关系的Set集合 Set<Map.Entry<String,String>> newSet = map.entrySet(); //获取set集合对应的迭代器 Iterator<Map.Entry<String,String>> ir = newSet.iterator(); //对映射关系进行迭代 while(ir.hasNext()){ //获取映射关系 Map.Entry<String,String> entry = ir.next(); //通过映射关系中的getKey与getValue方法取出集合中的元素 String key = entry.getKey(); String value = entry.getValue(); System.out.println(key+" -- "+value); } } public static void sop(Object obj){ System.out.println(obj); } }
2、对键进行排序
运行结果:import java.util.*; /* * 将学生对象及其归属地存入Map集合中 * 按学生的年龄进行排序 * * 思路:学生对象不重复,作为键。要排序就需要用到TreeMap集合 */ public class TreeMapDemo { public static void main(String[] args){ //定义集合用于存储学生对象及其归属地 TreeMap<Student,String> tm = new TreeMap<Student,String>(); tm.put(new Student("xiaoxiao5",17), "zunyi"); tm.put(new Student("xiaoxiao1",16), "guiyang"); tm.put(new Student("xiaoxiao2",19), "miaotang"); tm.put(new Student("xiaoxiao3",18), "zhengan"); //取出集合中的元素 Iterator<Student> it = tm.keySet().iterator(); while(it.hasNext()){ Student stu = it.next(); String value = tm.get(stu); System.out.println(stu+" "+value); } } } //定义Student实现Comparable接口,让Student具备比较性 class Student implements Comparable<Student>{ private String name; private int age; //私有成员的set与get方法、equals方法、hashCode方法由于未用到故未定义 Student(String name,int age){ this.name = name; this.age = age; } //覆盖compareTo方法 public int compareTo(Student s){ int num = new Integer(this.age).compareTo(new Integer(s.age)); if(num==0) return this.name.compareTo(s.name); return num; } public String toString(){ return name+" - "+age; } }
3、集合嵌套
运行结果:import java.util.*; /* * 需求:集合嵌套演示 * 定义一个Map集合czbk(学校),里面存放的是班级名称和班级 * 班级yure是一个集合,里面存放的是学号和学生 * 班级jiuye也是一个集合,里面存放的是学号和学生 */ public class DoubleMap { public static void main(String[] args){ //定义czbk的Map集合,用于存储班级名称和班级的集合 TreeMap<String,TreeMap<String,Student>> czbk = new TreeMap<String,TreeMap<String,Student>>(); //定义yure与jiuye的班级集合,里面存放的是学号与学生 TreeMap<String,Student> yure = new TreeMap<String,Student>(); TreeMap<String,Student> jiuye = new TreeMap<String,Student>(); //向czbk中添加键(班级名称)与值(班级的集合) czbk.put("YuReBan", yure); czbk.put("JiuYeBan", jiuye); //向班级yure与jiuye中添加键(学号)与值(学生) yure.put("01号", new Student("zenghan01",24)); yure.put("02号", new Student("zenghan02",22)); jiuye.put("01号", new Student("diudiu01",25)); jiuye.put("02号", new Student("diudiu02",21)); //获取czbk中键(班级名称)的Set集合的迭代器 Iterator<String> ItRoomName = czbk.keySet().iterator(); while(ItRoomName.hasNext()){ //依次获取班级名称 String roomName = ItRoomName.next(); //通过czbk获取键对应的值(班级的Map集合) Map<String,Student> room = czbk.get(roomName); System.out.println(roomName); //获取班级集合中键(学号)的set集合 Iterator<String> itNum = room.keySet().iterator(); while(itNum.hasNext()){ //一次获取学号 String num = itNum.next(); //通过学号获取学生对象 Student student = room.get(num); System.out.println(num+" "+student); } } } } //描述学生 class Student{ private String name; private int age; Student(String name,int age){ this.name = name; this.age = age; } //复写hashCode方法 public int hashCode(){ return name.hashCode()+age*29; } //复写equals方法 public boolean equals(Object obj){ if(!(obj instanceof Student)) throw new ClassCastException(); Student s = (Student)obj; return this.name.equals(s.name) && this.age == s.age; } public String toString(){ return name+" - "+age; } }
3、记录字符串中字符出现的次数
运行结果:package day.day5; import java.util.*; /* * 定义一个功能,计算字符串中各个字符出现的次数 * a(1)b(3)... * * 思路:有映射关系---Map集合 * 有顺序 ------TreeMap集合 * * 将字符串转换成数组后,将每一个字符作为Key取查TreeMap集合,若有,则++,再put(该字符,次数) 没有则put该字符 ,1 * * Character自身具备比较性 (自然顺序) */ public class CharatorCount { public static void main(String[] args){ String str = "adsfkkvczdga"; String newStr = countOfChar(str); System.out.println(newStr); } public static String countOfChar(String str){ //将字符串转换成字符数组 char[] chs = str.toCharArray(); //定义TreeMap集合用于存储字母与次数的映射关系 TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>(); //int count = 0;//定义计数器 //对数组进行遍历 for(int x=0;x<chs.length;x++){ //拿对应字符去查TreeMap集合 Integer value = tm.get(chs[x]); //元素不存在则将该字符与1存入该集合 if(value==null){ tm.put(chs[x], 1); } else{ //若元素存在则次数自增后,再将该字符与对应次数存入该集合 value++; tm.put(chs[x], value); } /* * 替换if else * if(value!=null)//如果该字符已在集合中存在,则获取次数 * count = value; * count++;//不管存在不存在次数都自增 * tm.put(chs[x],count)//将字符与对应次数存入集合 * count=0;//对次数清零,否则重合 */ } //定义字符串缓冲区 StringBuilder sb = new StringBuilder(); //获取Map集合中字符的集合 Iterator<Character> it = tm.keySet().iterator(); while(it.hasNext()){ Character key = it.next(); Integer value = tm.get(key); //按指定格式存入数据 sb.append(key+"("+value+")"); } //返回指定格式的数据 return sb.toString(); } }
第七部分:Collections静态工具类
一、与Collection的区别
Collection:集合框架的一个顶层接口。
Collections:集合框架工具类。
二、常用方法
1、对List集合的排序
由于List集合中没有排序方法,Collections可以对List集合进行排序。(不能对Set集合进行排序,因为TreeSet已能排序)
public static <T extends Comparable<? super T>> void sort(List<T> list) 对list集合按自然顺序进行排序
public static <T> void sort(List<T> list,Comparator<? super T> c) 对list集合按指定比较器进行排序
2、获取最值
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
根据元素的自然顺序,返回给定 collection 的最大元素。(也可以指定比较器)
public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp)
根据指定比较器产生的顺序,返回给定 collection 的最小元素。 (也可以按自然顺序)
3、折半查找(有序集合是前提)
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key)
使用二分搜索法搜索指定列表,以获得指定对象。不存在则返回 -(插入点)-1
public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
指定比较器,使用二分搜索法搜索指定列表,以获得指定对象。不存在则返回 -(插入点)-1
4、替换
public static <T> void fill(List<? super T> list, T obj) 使用指定元素替换指定列表中的所有元素
public static <T> void copy(List<? super T> dest, List<? extends T> src)
将所有元素从一个列表复制到另一个列表
public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal)
使用另一个值替换列表中出现的所有某一指定值
5、比较器的强行逆转
public static void reverse(List<?> list) 反转指定列表中元素的顺序
public static <T> Comparator<T> reverseOrder()
返回一个比较器,它强行逆转实现了 Comparable 接口的对象 collection 的自然顺序
public static <T> Comparator<T> reverseOrder(Comparator<T> cmp)
返回一个比较器,它强行逆转指定比较器的顺序
6、交换元素的位置
public static void swap(List<?> list, int i, int j) 在指定列表的指定位置处交换元素
public static void shuffle(List<?> list) 使用默认随机源对指定列表进行置换
public static void shuffle(List<?> list, Random rnd) 使用指定的随机源对指定列表进行置换
6、获取同步集合
给定一个线程不安全的集合,返回一个线程安全的集合:
public static <T> Collection<T> synchronizedCollection(Collection<T> c)
public static <T> List<T> synchronizedList(List<T> list)
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
public static <T> Set<T> synchronizedSet(Set<T> s)
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)
第八部分:Arrays静态工具类
一、常用方法
1、折半查找(有序数组是前提)
基本数据类型的数组:
public static int binarySearch(char[] a,char key) 使用二分搜索法对key进行查找。不存在则返回 -(插入点)-1
pubilc static int binarySearch(char[] a, int fromIndex, int toIndex, char key) 指定查找的范围
引用类型数组:
public static int binarySearch(Object[] a, Object key) 元素自身具备比较器(实现Comparable接口)
public static int binarySearch(Object[] a, int fromIndex, int toIndex, Object key)
public static <T> int binarySearch(T[] a, T key, Comparator<? super T> c) 指定比较器(实现Comparator接口)
public static <T> int binarySearch(T[] a, int fromIndex, int toIndex, T key, Comparator<? super T> c)
2、排序
基本数据类型数组:
public static void sort(byte[] a) 对数组进行升序排序
public static void sort(byte[] a, int fromIndex, int toIndex) 指定排序的范围
引用类型数组:
public static void sort(Object[] a)
public static void sort(Object[] a, int fromIndex, int toIndex)
public static <T> void sort(T[] a, Comparator<? super T> c)
public static <T> void sort(T[] a, int fromIndex, int toIndex, Comparator<? super T> c)
3、复制
基本数据类型数组:
public static int[] copyOf(int[] original, int newLength) 复制指定的数组,截取或用 0 填充(如有必要),使其具有指定长度
public static int[] copyOfRange(int[] original, int from, int to) 复制一个范围
引用类型数组:
public static <T> T[] copyOf(T[] original, int newLength) 复制指定的数组,截取或用 null 填充(如有必要)
public static <T> T[] copyOfRange(T[] original, int from, int to) 复制一个范围
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType)
public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType)
4、比较
基本数据类型数组:
public static boolean equals(double[] a, double[] a2) 比较两个数组的内容是否相等(包括顺序)
引用类型数组:
public static boolean equals(Object[] a,Object[] a2) 用equals方法来比较
深层比较:
public static boolean deepEquals(Object[] a1, Object[] a2) Object[]中存放的可以是数组
5、替换
基本数据类型数组:
public static void fill(long[] a, long val) 用val替换数组中的每一个元素
public static void fill(long[] a, int fromIndex, int toIndex, long val) 替换一个范围
引用类型数组:
public static void fill(Object[] a, Object val)
public static void fill(Object[] a, int fromIndex, int toIndex, Object val)
6、转换成字符串
public static String toString(int[] a) 将数组中的内容转换成字符串(包含[])
public static String toString(Object[] a) 此方法等效于 Arrays.asList(a).toString()public static String deepToString(Object[] a) 返回指定数组“深层内容”的字符串表示形式
二、集合与数组之间的转换
1、数组转换成集合
1)实现方法
public static <T> List<T> asList(T... a) 将数组转换成List集合
2)好处
可以使用集合的思想或方法来操作数组,如判断数组中是否包含某一个元素时,使用数组需要遍历,而使用List集合时可以使用contains方法直接判断。
3)注意事项
(a)将数组变成集合,不可以使用集合的增删方法,因为数组的长度是固定的。如果使用增删操作,会发生UnspportedOperationException(不支持操作异常)。
(b)如果数组中的元素都是对象,数组中的元素就可以直接转换成为集合中的元素;如果数组中的元素是基本数据类型,那么就会将整个数组作为集合中的一个元素。
示例代码:
运行结果:package demo; /* * 需求:将基本数据类型数组和引用数据类型数组转换成集合 */ import java.util.Arrays; import java.util.List; public class ArraysDemo{ public static void main(String[] args){ int[] arr = {1,2,3}; String[] strs = {"java1","java2","java3"}; Integer[] ints = {4,5,6}; //将int[]转换成集合 List<int[]> list1 = Arrays.asList(arr); //将String[]转换成集合 List<String> list2 = Arrays.asList(strs); //将Integer[]转换成集合 List<Integer> list3 = Arrays.asList(ints); //对集合进行打印 print(list1); print(list2); print(list3); } public static void print(Object o){ System.out.println(o); } }
2、集合转换成数组
1、实现方法(Collection接口中)
Object[] toArray() 返回包含此 collection 中所有元素的数组
<T> T[] toArray(T[] a)
返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组a的运行时类型相同
示例代码:
运行结果:package demo; import java.util.ArrayList; import java.util.Arrays; /* * 需求:将集合转换成数组 */ public class CollectionsDemo{ public static void main(String[] args){ //定义List集合并添加元素 ArrayList<String> list = new ArrayList<String>(); list.add("java01"); list.add("java02"); list.add("java03"); String[] arr1 = new String[2];//长度小于集合的长度 String[] arr2 = new String[6];//长度大于集合的长度 //将集合转变成数组 String[] arr3 = list.toArray(arr1); String[] arr4 = list.toArray(arr2); //对集合进行打印 System.out.println(Arrays.toString(arr3)); System.out.println(Arrays.toString(arr4)); } }
由结果可以看出:
当指定类型数组的长度小于集合的size,那么该方法内部会创建一个新数组,长度为集合的size;
当指定类型数组的长度大于集合的size,就直接之用原来的数组,不再创建新数组。
因此,在定义指定类型数组时,长度为集合的size最优。
2、为何要将集合变成数组
将集合变成数组是为了限定对集合的操作,如不需要对集合元素进行增删了,就可以将该集合转换成数组。