黑马程序员—————Java基础----集合(二)set、map等
2015-08-23 15:05
676 查看
------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
第一讲 set接口
set:
|--HashSet
底层数据结构是哈希表,线程是不同步的。无序,高效。
哈希表这种结构其实就是对哈希值的存储。
|--TreeSet
TreeSet底层的数据结构就是二叉树。
对set集合中的元素进行指定顺序的排序。不同步。
1)下面对HashSet做详细介绍:
HashSet如何保证元素唯一性呢?
Hashset集合保证元素的唯一性:通过元素的hashCode方法和equals方法完成的。
a:当元素的hashCode值相同时,才继续判断元素的equals是否为true。
如果为true,那么视为相同元素,不存入;如果为false,那么存储。
b: 如果hashCode值不同,那么不判断equals,从而提高对象比较的速度。
哈希表的原理:
1、对对象元素中的关键字(对象中的特有数据),进行哈希算法的运算,并得出一个具体的算法值,这个值 称为哈希值。
2、哈希值就是这个元素的位置。
3、如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同,就不存储,因为元素重复。如果对象不同,就存储,在原来对象的哈希值基础 +1顺延。
4、存储哈希值的结构,我们称为哈希表。
5、既然哈希表是根据哈希值存储的,为了提高效率,最好保证对象的关键字是唯一的。
这样可以尽量少的判断关键字对应的对象是否相同,提高了哈希表的操作效率。
对于ArrayList集合,判断元素是否存在,或者删元素底层依据都是equals方法。
对于HashSet集合,判断元素是否存在,或者删除元素,底层依据的是hashCode方法和equals方法。
小练习:1、HashSet存储字符串并遍历
2)下面对TreeSet做详细介绍:
1)TreeSet:根据构造方法的不用,选择使用自然排序或者比较器排序。
按照实际的需求,可以对元素进行排序。并且保证唯一。
2)怎么保证的呢?
排序:底层结构是二叉树。按照树节点进行存储和取出。
两种实现:
A:自然排序(元素具备比较性)
TreeSet的无参构造,要求对象所属的类实现Comparable接口。
B:比较器排序(集合具备比较性)
TreeSet的带参构造,要求构造方法接收一个实现了Comparator接口的对象。
唯一:根据返回值是否为0。
注意:
如果同时有两种方案,以谁为主呢? 以比较器为主。
![](http://img.blog.csdn.net/20150824144941501?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
案例:对对象的年龄排序和姓名排序。
在集合中的数据结构问题
ArrayXxx:底层数据结构是数组。查询快,增删慢。
LinkedXxx:底层数据结构是链表。查询慢,增删快。
HashXxx:底层数据结构是哈希表。跟两个有关。hashCode()和equals()
TreeXxx:底层数据结构是二叉树。两种排序方式。Comparable接口和Comparator接口
3)什么时候,使用哪种Collection集合。
元素唯一吗?
唯一:
Set
需要排序吗?
需要:TreeSet
不需要:HashSet
不知道,用HashSet。
不唯一:
List
需要安全码?
需要:Vector
不需要:ArrayList和LinkedList
查询多:ArrayList
增删多;LinkedList
不知道,用ArrayList。
第二讲 Map
Map概述:在很多时候,比如存储学生信息,要求学号和学生一一对应,就所学的知识,只能用二维数组,或者一个Set和一个个List组合来表达。但是这样的话就创建了多个容器,不好。这样Java就提供了一个新的集合:Map
Map是一个键值对形式的集合,它的数据不再是单个的了,必须同时有键和值组成。最大优点就是:体现对应关系。
1)Map和Collection的区别?
Map:是(键值对)双列形式的集合,键必须是唯一的,不能重复,值可以重复。(看成是夫妻对的集合)
Collection:是单列值的集合;Collection的儿子,是可以重复的,他的Set儿子是唯一的(看成是单身汉的集合)
2)Map接口的功能:
A:增加功能
V put(K key,V value):当key在集合中不存在时,添加元素;当key在集合存在时候,替换元素。
B:删除功能
void clear():清除所有键值对数据。
V remove(Object key):根据指定的键删除键值对。
C:判断功能
boolean containsKey(Object key):判断指定的键是否在集合中存在
boolean containsValue(Object vlaue):判断指定的值是否在集合中存在
boolean isEmpty():判断集合是否为空
D:获取功能
Set<Map.Entry<K,V>> entrySet():键值对对象的集合。
Object get(Object key):根据键获取值
Set<K> keySet():所有键的集合
Collection<V> values():所有值的集合
E:长度功能
int size()
注意:Map集合中的具体实现类的数据结构,是针对键有效。
小练习:
单独获取键和值的练习:
方式2:通过结婚证找丈夫和妻子
Entry的实现:
3)HashMap
(1)HashMap存储字符串并遍历
键:String
值:String
(2)HashMap存储自定义对象并遍历
键:String
值:Student
(3)HashMap存储自定义对象并遍历
键:Student
值:String
需求:如果对象的成员变量值都相同,我们则认为是同一个对象。
4)TreeMap
(1)TreeMap存储字符串并遍历
键:String
值:String
(2)TreeMap存储自定义对象并遍历
键:Student
值:String
需求:如果对象的成员变量值都相同,我们则认为是同一个对象。
同时,我们还要按照年龄排序。
5)面试题:Hashtable和HashMap的区别?
代码体现:
运行结果如下:
![](http://img.blog.csdn.net/20150825125305032?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
5)Map体系的面试题:
1、"cbxzbvavdvgd"获取字符串中,每一个字母出现次数:"a(1)b(2)c(1)d(2)g(1)v(3)x(1)z(1)"
![](http://img.blog.csdn.net/20150825152204108?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
Map的嵌套:
1、HashMap内嵌套HashMap集合
![](http://img.blog.csdn.net/20150825160851255?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
2、HashMap内嵌套ArrayList集合
1:集合体系(掌握)
集合
|--Collection(单列)
|--List(有序,可重复)
|--ArrayList
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高。
|--Vector
底层数据结构是数组,查询快,增删慢。
线程安全,效率低。
|--LinkedList
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高。
|--Set(无序,唯一)
|--HashSet
底层数据结构是哈希表。
线程不安全,效率高。
怎么保证唯一性的呢?
它依赖两个方法:hashCode()和equals()
顺序:
首先判断hashCode()值是否相同。
同:继续走equals(),看返回值
如果true:就不添加到集合。
如果false:就添加到集合。
不同:就添加到集合。
|--TreeSet
底层数据结构是二叉树。
线程不安全,效率高。
怎么保证唯一性的呢? 是根据返回是否是0。
怎么保证排序的呢? 两种方式:
1) 自然排序(元素具备比较性)
实现Comparable接口
2)比较器排序(集合具备比较性)
实现Comparator接口
|--Map(双列 底层结构是针对键有效,跟值无关)
|--HashMap
底层数据结构是哈希表。
线程不安全,效率高。
怎么保证唯一性的呢?
它依赖两个方法:hashCode()和equals()
顺序:
首先判断hashCode()值是否相同。
同:继续走equals(),看返回值
如果true:就不添加到集合。
如果false:就添加到集合。
不同:就添加到集合。
|--Hashtable
底层数据结构是哈希表。
线程安全,效率低。
怎么保证唯一性的呢?
它依赖两个方法:hashCode()和equals()
顺序:
首先判断hashCode()值是否相同。
同:继续走equals(),看返回值
如果true:就不添加到集合。
如果false:就添加到集合。
不同:就添加到集合。
|--TreeMap
底层数据结构是二叉树。
线程不安全,效率高。
怎么保证唯一性的呢?
是根据返回是否是0。
怎么保证排序的呢?两种方式
自然排序(元素具备比较性)
实现Comparable接口
比较器排序(集合具备比较性)
实现Comparator接口
2:应用。(添加功能,判断功能,删除功能,获取功能,长度功能)
Collection
add(Object obj)
remove(Object obj)
contains(Object obj)
iterator()
size()
|--List
get(int index)
add(int index,Object obj)
remove(int index)
set(int index,Object obj)
|--Set
Map
put(Object key,Object value)
remove(Object key)
containsKey(Object key)
containsValue(Object value)
size()
get(Object key)
keySet()
values()
3:遍历方式
List:
迭代器(在源码中可以看到的,开发中也经常看到)
增强for(开发中看到,JDK5以后用)
普通for
如果仅仅为了遍历,用任意一种即可。一般选择前两种的任意一种。
如果要做修改,或者删除指定位置的元素,或者在指定位置添加元素。用普通for。
Set:
迭代器
增强for
任选一种。
Map:
键找值。
4:代码补齐:请对array,hs,hm进行遍历。
A: ArrayList<String> array = new ArrayList<String>();
方式1:
Iterator<String> it = array.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
方式2:
for(String s : array){
System.out.println(s);
}
方式3:
for(int x=0; x<array.size(); x++){
String s = array.get(x);
System.out.println(s);
}
B:HashSet<String> hs = new HashSet<String>();
方式1:
Iterator<String> it = hs.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
方式2:
for(String s : hs)
{
System.out.println(s);
}
C: HashMap<String,Strting> hm = new HashMap<String,String>();
Set<String> set = hm.keySet();
for(String key : set)
{
String value = hm.get(key);
System.out.println(key+"***"+value);
}
5:什么时候用谁?
是否键值对?
是:Map
是否对键排序?
是:TreeMap
否:HashMap
不懂的情况下,使用HashMap。
否:Collection
是否唯一
是:Set
是否对元素进行排序?
是:TreeSet
否:HashSet
不懂的情况下,使用HashSet
否:List
是否要安全:
是:Vector(真正开发中也不用)
List list = Collections.synchronizedList(new ArrayList());
否:ArrayList,LinkedList
查询多:ArrayList
增删多:LinkedList
不懂的情况下,使用ArrayList
有不对的地方希望大家给我指正出来,谢谢!! 谢谢浏览~~
------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
第一讲 set接口
set:
|--HashSet
底层数据结构是哈希表,线程是不同步的。无序,高效。
哈希表这种结构其实就是对哈希值的存储。
|--TreeSet
TreeSet底层的数据结构就是二叉树。
对set集合中的元素进行指定顺序的排序。不同步。
1)下面对HashSet做详细介绍:
HashSet如何保证元素唯一性呢?
Hashset集合保证元素的唯一性:通过元素的hashCode方法和equals方法完成的。
a:当元素的hashCode值相同时,才继续判断元素的equals是否为true。
如果为true,那么视为相同元素,不存入;如果为false,那么存储。
b: 如果hashCode值不同,那么不判断equals,从而提高对象比较的速度。
哈希表的原理:
1、对对象元素中的关键字(对象中的特有数据),进行哈希算法的运算,并得出一个具体的算法值,这个值 称为哈希值。
2、哈希值就是这个元素的位置。
3、如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同,就不存储,因为元素重复。如果对象不同,就存储,在原来对象的哈希值基础 +1顺延。
4、存储哈希值的结构,我们称为哈希表。
5、既然哈希表是根据哈希值存储的,为了提高效率,最好保证对象的关键字是唯一的。
这样可以尽量少的判断关键字对应的对象是否相同,提高了哈希表的操作效率。
对于ArrayList集合,判断元素是否存在,或者删元素底层依据都是equals方法。
对于HashSet集合,判断元素是否存在,或者删除元素,底层依据的是hashCode方法和equals方法。
小练习:1、HashSet存储字符串并遍历
/* HashSet存储字符串并遍历 */ public class HashSetDemo { public static void main(String[] args) { // 创建集合对象 HashSet<String> hs = new HashSet<String>(); // 创建并添加元素 hs.add("hello"); hs.add("world"); hs.add("java"); hs.add("java"); // 遍历 for (String s : hs) { System.out.println(s); } } }2、HashSet存储自定义对象。
/* * HashSet存储自定义对象。 * 需求:我们认为一个对象如果成员变量值都相同,则为同一个对象。 * * 请思考: * A:哪里出问题了 * 通过简单的分析,我们知道了在add方法出问题了。 * B:怎么解决 * 看源码 * 通过看源码:我们知道,最终的操作跟如下这个判断相关 * if(e.hash == hash && ((k = e.key) == key || key.equals(k))) * { * 唯一。 * } * 分析条件: * A:这个判断跟对象的hashCode()方法相关。 * B:这个判断跟equals()方法相关。 * * * 总结: * HashSet如何保证元素的唯一性的呢? * HashSet的底层数据结构是哈希表。 * 它依赖两个方法,hashCode()和equals()。 * 顺序: * 首先,判断对象的hashCode()值是否相同。 * 相同: * 继续走equals()。看返回值是true还是false * A:如果是true,说明有元素重复。该元素不添加到集合。 * B:如果是false,说明元素不重复,该元素添加到集合。 * 不同:就直接添加到集合中了。 * hashCode():把所有成员变量值相加。如果是引用类型,用哈希值。如果是基本类型直接用值。 * Person: * String name; * int age; * char sex; * float score; * * public int hashCode() * { * return this.name.hashCode()+this.age*13+this.sex*17+this.score*21; * } * equals():三步。 * A:this == obj * B:!(obj instanceof Student) * C:this.name.equals(s.name) && this.age == s.age && this.sex == s.sex && this.score == s.socre; * 会但是不用记。理解即可。 * 开发不这样用。怎么用呢? * 自动生成。 */ 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; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } } public class HashSetDemo2 { public static void main(String[] args) { // 创建集合对象 HashSet<Student> hs = new HashSet<Student>(); // 创建元素对象 Student s1 = new Student("301宿舍--笨笨", 26); Student s2 = new Student("301宿舍--姗姗", 36); Student s3 = new Student("301宿舍--红红", 20); Student s4 = new Student("301宿舍--笨笨", 26); Student s5 = new Student("301宿舍--歪歪", 66); Student s6 = new Student("301宿舍--媛媛", 16); // 添加元素 hs.add(s1); // hs.add(s1); hs.add(s2); hs.add(s3); hs.add(s4); hs.add(s5); hs.add(s6); // 遍历 for (Student s : hs) { System.out.println(s.getName() + "***" + s.getAge()); } } }
2)下面对TreeSet做详细介绍:
1)TreeSet:根据构造方法的不用,选择使用自然排序或者比较器排序。
按照实际的需求,可以对元素进行排序。并且保证唯一。
2)怎么保证的呢?
排序:底层结构是二叉树。按照树节点进行存储和取出。
两种实现:
A:自然排序(元素具备比较性)
TreeSet的无参构造,要求对象所属的类实现Comparable接口。
B:比较器排序(集合具备比较性)
TreeSet的带参构造,要求构造方法接收一个实现了Comparator接口的对象。
唯一:根据返回值是否为0。
注意:
如果同时有两种方案,以谁为主呢? 以比较器为主。
案例:对对象的年龄排序和姓名排序。
<span style="font-size:14px;">import java.util.TreeSet; /* * TreeSet存储自定义对象。 * 保证元素有序和唯一。 * * Exception in thread "main" java.lang.ClassCastException: * cn.itcast_03.Student cannot be cast to java.lang.Comparable * * TreeSet保证元素排序有两种方式: * A:自然顺序 让对象所属的类去实现Comparable接口。无参构造。 * B:比较器接口 Comparator。带参构造。 * * 在自然排序中,又是如何保证排序的呢? * 根据返回值看: * 正 就说明元素比以前的元素大,往后放。 * 负 就说明元素比以前的元素小,往前放。 * 0 元素就不添加到集合中。着就是保证唯一性的原理。 * * 需求:我想按照对象的年龄排序,从小到大排序。怎么做? * * 需求:我想按照姓名的长度排序,从小到大排序。怎么做? */ //标准学生类 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 int compareTo(Student s) { // // 需求是比较年龄 // int num = this.age - s.age; // // 由于对象有多个成员变量,你不能根据其中的某一个决定其他的。 // // 当某一个相同的时候,你还需要判断其他的是不是也是相同的。 // int num2 = (num == 0) ? (this.name.compareTo(s.name)) : num; // return num2; // } // 需求:我想按照姓名的长度排序,从小到大排序。怎么做? @Override public int compareTo(Student s) { // 姓名的长度 int num = this.name.length() - s.name.length(); // 很多时候,别人给我们的需求其实只是一个主要需要 // 还有很多的次要需求是需要我们自己进行分析的。 // 比较姓名的内容 int num2 = (num == 0) ? (this.name.compareTo(s.name)) : num; // 继续分析,姓名长度和内容都相同的情况下,年龄还可能不一样呢? // 所以,当姓名长度和内容都相同的时候,我们在比较下年龄就好了 int num3 = (num2 == 0) ? (this.age - s.age) : num2; return num3; } } public class TreeSetDemo2 { public static void main(String[] args) { // 创建集合对象 TreeSet<Student> ts = new TreeSet<Student>(); // 创建元素对象 Student s1 = new Student("liudehua", 52); Student s2 = new Student("chenglong", 60); Student s3 = new Student("zhouxinchi", 44); Student s4 = new Student("sunyanzi", 34); Student s5 = new Student("linqingxia", 26); Student s6 = new Student("linqingxia", 36); Student s7 = new Student("linqing", 26); Student s8 = new Student("linqingxia", 26); // 添加元素 ts.add(s1); ts.add(s2); ts.add(s3); ts.add(s4); ts.add(s5); ts.add(s6); ts.add(s7); ts.add(s8); // 遍历 for (Student s : ts) { System.out.println(s.getName() + "***" + s.getAge()); } } } </span>总结:
在集合中的数据结构问题
ArrayXxx:底层数据结构是数组。查询快,增删慢。
LinkedXxx:底层数据结构是链表。查询慢,增删快。
HashXxx:底层数据结构是哈希表。跟两个有关。hashCode()和equals()
TreeXxx:底层数据结构是二叉树。两种排序方式。Comparable接口和Comparator接口
3)什么时候,使用哪种Collection集合。
元素唯一吗?
唯一:
Set
需要排序吗?
需要:TreeSet
不需要:HashSet
不知道,用HashSet。
不唯一:
List
需要安全码?
需要:Vector
不需要:ArrayList和LinkedList
查询多:ArrayList
增删多;LinkedList
不知道,用ArrayList。
第二讲 Map
Map概述:在很多时候,比如存储学生信息,要求学号和学生一一对应,就所学的知识,只能用二维数组,或者一个Set和一个个List组合来表达。但是这样的话就创建了多个容器,不好。这样Java就提供了一个新的集合:Map
Map是一个键值对形式的集合,它的数据不再是单个的了,必须同时有键和值组成。最大优点就是:体现对应关系。
1)Map和Collection的区别?
Map:是(键值对)双列形式的集合,键必须是唯一的,不能重复,值可以重复。(看成是夫妻对的集合)
Collection:是单列值的集合;Collection的儿子,是可以重复的,他的Set儿子是唯一的(看成是单身汉的集合)
2)Map接口的功能:
A:增加功能
V put(K key,V value):当key在集合中不存在时,添加元素;当key在集合存在时候,替换元素。
B:删除功能
void clear():清除所有键值对数据。
V remove(Object key):根据指定的键删除键值对。
C:判断功能
boolean containsKey(Object key):判断指定的键是否在集合中存在
boolean containsValue(Object vlaue):判断指定的值是否在集合中存在
boolean isEmpty():判断集合是否为空
D:获取功能
Set<Map.Entry<K,V>> entrySet():键值对对象的集合。
Object get(Object key):根据键获取值
Set<K> keySet():所有键的集合
Collection<V> values():所有值的集合
E:长度功能
int size()
注意:Map集合中的具体实现类的数据结构,是针对键有效。
小练习:
单独获取键和值的练习:
/* * Set<K> keySet():所有键的集合 * Collection<V> values():所有值的集合 */ public class MapDemo2 { public static void main(String[] args) { // 创建集合对象 Map<Integer, String> map = new HashMap<Integer, String>(); // 创建并添加元素 map.put(1, "貂蝉"); map.put(2, "黄忠"); map.put(3, "赵云"); // 显示数据 // System.out.println(map); // Set<K> keySet():所有键的集合 Set<Integer> set = map.keySet(); for (Integer i : set) { System.out.println(i); } System.out.println("----------"); // Collection<V> values():所有值的集合 Collection<String> con = map.values(); for (String str : con) { System.out.println(str); } } }根据键获取值:
/* * Object get(Object key):根据键获取值 * Map集合的遍历。 * 方式1:丈夫找妻子 * A:把所有丈夫给集中起来。Set<K> keySet() * B:遍历丈夫集合,获取到每一个丈夫。迭代器,增强for * C:让丈夫去找妻子。get(Object key) */ public class MapDemo3 { public static void main(String[] args) { // 创建集合对象 Map<String, String> map = new HashMap<String, String>(); // 创建并添加元素 map.put("杨过", "小龙女"); map.put("郭靖", "黄蓉"); map.put("梁山伯", "祝英台"); map.put("牛郎", "织女"); // 键的集合 Set<String> set = map.keySet(); for (String str : set) { System.out.println(str); } System.out.println("---------"); // 值的集合 Collection<String> con = map.values(); for (String str : con) { System.out.println(str); } System.out.println("---------"); // 根据键获取值 // Object get(Object key):根据键获取值 System.out.println(map.get("郭靖")); System.out.println(map.get("牛郎")); System.out.println(map.get("田野")); System.out.println("---------"); // 遍历 // A:把所有丈夫给集中起来。Set<K> keySet() Set<String> husbandSet = map.keySet(); // B:遍历丈夫集合,获取到每一个丈夫。迭代器,增强for for (String husband : husbandSet) { // C:让丈夫去找妻子。get(Object key) String wife = map.get(husband); System.out.println(husband + "***" + wife); } } }
方式2:通过结婚证找丈夫和妻子
/* * Map集合的遍历。 * 方式2:通过结婚证找丈夫和妻子。 * A:获取所有结婚证的集合。Set<结婚证> entrySet() * class 结婚证<K,V> * { * private K key; * private V value; * * public 结婚证(K key,V value) * { * this.key = key; * this.value = value; * } * * public K getKey() * { * return key; * } * * public V getValue() * { * return value; * } * } * B:遍历结婚证集合,获取到每一个结婚证对象。迭代器,增强for。 * C:通过结婚证对象获取丈夫和妻子。 */ public class MapDemo4 { public static void main(String[] args) { // 创建集合对象 Map<String, String> map = new HashMap<String, String>(); // 创建并添加元素 map.put("杨过", "小龙女"); map.put("郭靖", "黄蓉"); map.put("梁山伯", "祝英台"); map.put("牛郎", "织女"); // 获取结婚证的集合 // Set<Map.Entry<K,V>> entrySet():键值对对象的集合。 Set<Map.Entry<String, String>> set = map.entrySet(); // 遍历结婚证集合,获取到每一个结婚证对象 for (Map.Entry<String, String> me : set) { // 通过结婚证对象获取丈夫和妻子。 String key = me.getKey(); String value = me.getValue(); System.out.println(key + "***" + value); } } }
Entry的实现:
/* *1:找到Entry的实现。 *2:将来导包的时候: * 你使用Map.Entry,就导入到Map * 你使用Entry,就导入到Map.Entry */ public class MapDemo5 { public static void main(String[] args) { // 创建集合对象 HashMap<String, String> map = new HashMap<String, String>(); // 创建并添加元素 map.put("杨过", "小龙女"); map.put("郭靖", "黄蓉"); map.put("梁山伯", "祝英台"); map.put("牛郎", "织女"); // 获取结婚证的集合 // Set<Map.Entry<K,V>> entrySet():键值对对象的集合。 Set<Map.Entry<String, String>> set = map.entrySet(); // 遍历结婚证集合,获取到每一个结婚证对象 for (Entry<String, String> me : set) { // 通过结婚证对象获取丈夫和妻子。 String key = me.getKey(); String value = me.getValue(); System.out.println(key + "***" + value); } // 看源码。 // static class Entry<K,V> implements Map.Entry<K,V> } }
3)HashMap
(1)HashMap存储字符串并遍历
键:String
值:String
/* * HashMap存储键和值。并遍历。 * 键:String * 值:String */ public class HashMapDemo { public static void main(String[] args) { // 创建集合对象 HashMap<String, String> hm = new HashMap<String, String>(); // 创建并添加元素 hm.put("刘备", "孙尚香"); hm.put("曹操", "卞氏"); hm.put("孙权", "步练氏"); // 遍历 Set<String> set = hm.keySet(); for (String key : set) { String value = hm.get(key); System.out.println(key + "***" + value); } System.out.println("---------------------"); // 遍历2 Set<Map.Entry<String, String>> hmSet = hm.entrySet(); for (Map.Entry<String, String> me : hmSet) { String key = me.getKey(); String value = me.getValue(); System.out.println(key + "***" + value); } } }
(2)HashMap存储自定义对象并遍历
键:String
值:Student
/* * HashMap存储键和值。并遍历。 * 键:String 学号 * 值:Student (name,age) */ public class HashMapDemo2 { public static void main(String[] args) { // 创建集合对象 HashMap<String, Student> hm = new HashMap<String, Student>(); // 创建元素对象 Student s1 = new Student("李世民", 30); Student s2 = new Student("朱元璋", 40); Student s3 = new Student("武则天", 50); // 添加元素 hm.put("it001", s1); hm.put("it002", s2); hm.put("it003", s3); // 遍历 Set<String> set = hm.keySet(); for (String key : set) { Student value = hm.get(key); System.out.println(key + "***" + value.getName() + "***" + value.getAge()); } // 遍历2 Set<Map.Entry<String, Student>> hmSet = hm.entrySet(); for (Map.Entry<String, Student> me : hmSet) { String key = me.getKey(); Student value = me.getValue(); System.out.println(key + "***" + value.getName() + "***" + value.getAge()); } } }
(3)HashMap存储自定义对象并遍历
键:Student
值:String
需求:如果对象的成员变量值都相同,我们则认为是同一个对象。
/* * HashMap存储键和值。并遍历。 * 键:Student (name,age) * 值:String 学号 * * 特有需求:两个对象的成员变量值如果都相同。我们则认为是同一个对象。 */ public class HashMapDemo3 { public static void main(String[] args) { // 创建集合对象 HashMap<Student, String> hm = new HashMap<Student, String>(); // 创建元素对象 Student s1 = new Student("李世民", 30); Student s2 = new Student("朱元璋", 40); Student s3 = new Student("武则天", 50); Student s4 = new Student("武则天", 50); Student s5 = new Student("武则天", 30); // 添加元素 hm.put(s1, "it001"); hm.put(s2, "it002"); hm.put(s3, "it003"); hm.put(s4, "it004"); hm.put(s5, "it005"); // 遍历 Set<Student> set = hm.keySet(); for (Student key : set) { String value = hm.get(key); System.out.println(key.getName() + "***" + key.getAge() + "***" + value); } } }
4)TreeMap
(1)TreeMap存储字符串并遍历
键:String
值:String
/* * TreeMap存储String类型的键和值。 */ public class TreeMapDemo { public static void main(String[] args) { TreeMap<String, String> tm = new TreeMap<String, String>(); // 创建并添加元素 tm.put("yangguo", "xiaolongnv"); tm.put("guojing", "huangrong"); tm.put("niulang", "zhinv"); // 遍历 Set<String> set = tm.keySet(); for (String key : set) { String value = tm.get(key); System.out.println(key + "***" + value); } } }
(2)TreeMap存储自定义对象并遍历
键:Student
值:String
需求:如果对象的成员变量值都相同,我们则认为是同一个对象。
同时,我们还要按照年龄排序。
/* * TreeMap存储自定义对象并遍历。 * 键:Student * 值:String * * 如果一个自定义对象做键,用TreeMap集合。 * 就必须要实现排序。 * 两种方式: * A:让自定义对象所属的类去实现Comparable接口 * B:使用带参构造方法,创建TreeMap,接收Comparator接口参数。 */ public class TreeMapDemo2 { public static void main(String[] args) { // 创建集合对象 TreeMap<Student, String> tm = new TreeMap<Student, String>( new Comparator<Student>() { @Override public int compare(Student s1, Student s2) { // int num = s1.getAge() - s2.getAge(); int num = s2.getAge() - s1.getAge(); int num2 = (num == 0) ? s1.getName().compareTo( s2.getName()) : num; return num2; } }); // 创建元素对象 Student s1 = new Student("李世民", 30); Student s2 = new Student("朱元璋", 40); Student s3 = new Student("武则天", 50); Student s4 = new Student("武则天", 50); Student s5 = new Student("武则天", 30); // 添加元素 tm.put(s1, "it001"); tm.put(s2, "it002"); tm.put(s3, "it003"); tm.put(s4, "it004"); tm.put(s5, "it005"); // 遍历 Set<Student> set = tm.keySet(); for (Student key : set) { String value = tm.get(key); System.out.println(key.getName() + "***" + key.getAge() + "***" + value); } } }
5)面试题:Hashtable和HashMap的区别?
代码体现:
/* <span style="white-space:pre"> </span> * Hashtable和HashMap的区别? <span style="white-space:pre"> </span> * A:Hashtable线程安全,效率低;不允许null键和值。 <span style="white-space:pre"> </span> * B:HashMap线程不安全,效率高;允许null键和值。 <span style="white-space:pre"> </span> */ <span style="white-space:pre"> </span>public class HashMapDemo { <span style="white-space:pre"> </span>public static void main(String[] args) { <span style="white-space:pre"> </span> HashMap<String, String> hm = new HashMap<String, String>(); <span style="white-space:pre"> </span> hm.put("hello", null); <span style="white-space:pre"> </span> hm.put(null, "world"); <span style="white-space:pre"> </span> hm.put(null, null); <span style="white-space:pre"> </span> System.out.println(hm); <span style="white-space:pre"> </span>System.out.println("**********"); <span style="white-space:pre"> </span>Hashtable<String, String> ht = new Hashtable<String, String>(); <span style="white-space:pre"> </span> ht.put("hello", null); <span style="white-space:pre"> </span> ht.put(null, "world"); <span style="white-space:pre"> </span> ht.put(null, null); <span style="white-space:pre"> </span>System.out.println(ht); <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>}
运行结果如下:
5)Map体系的面试题:
1、"cbxzbvavdvgd"获取字符串中,每一个字母出现次数:"a(1)b(2)c(1)d(2)g(1)v(3)x(1)z(1)"
/** * "cbxzbvavdvgd"获取字符串中,每一个字母出现次数:"a(1)b(2)c(1)d(2)g(1)v(3)x(1)z(1)" * 思路: * 1、把字符串变成字符数组 * 2、定义一个TreeMap集合。Character做键,Integer做值 * 3、遍历字符数组,获取每一个字符 * 4、拿到该字符,到TreeMap集合中找对应的值 * 5、根据返回值是否为null * 是:存储 ,把次数记录为1 * 否:把数据++,然后重写存储 * 6、把TreeMap的数据拼接成一个字符串 */ public class TreeMapDemo { public static void main(String[] args) { String s="cbxzbvavdvgd"; //把字符串变成字符数组 char[] chs=s.toCharArray(); //定义一个TreeMap集合。Character做键,Integer做值 TreeMap<Character, Integer> tm=new TreeMap<Character, Integer>(); //遍历字符数组,获取每一个字符 for (char ch:chs) { //拿到该字符,到TreeMap集合中找对应的值 Integer i=tm.get(ch); //根据返回值是否为null //是:存储,把次数记录为1 //否:把数据++,然后重写存储 if(i==null){ tm.put(ch,1); }else{ i++; tm.put(ch,i); } } //把TreeMap的数据拼接成一个字符串 StringBuilder sb=new StringBuilder(); Set<Character> set=tm.keySet(); for(Character ch:set){ Integer i=tm.get(ch); sb.append(ch).append("(").append(i).append(")"); } String result=sb.toString(); System.out.println(result); } }运行结果 :
Map的嵌套:
1、HashMap内嵌套HashMap集合
/** * 案例:遍历以下信息: * 信息工程系(xxgc): * 20120581 通信工程专业 * 20120591 软件工程专业 *通信工程专业 : * 01 zhangsan * 02 lisi * 软件工程专业: * 01 wangwu * 02 zhaoliu *思路:Map的嵌套使用。 * 1、定义一个HashMap集合。String做键,HashMap做值 * 2、往集合中添加元素。 * 3、最后用增强for遍历输出。 */ public class HashMapDemo2 { public static void main(String[] args) { //创建集合对象 HashMap<String,HashMap<String, String>> xxgc=new HashMap<String, HashMap<String,String>>(); //创建元素 HashMap<String, String> tx = new HashMap<String, String>(); tx.put("01","zhangsan"); tx.put("02","lisi"); xxgc.put("tx", tx); HashMap<String, String> rg = new HashMap<String, String>(); rg.put("01", "wangwu"); rg.put("02", "zhaoliu"); xxgc.put("rg",rg); // 遍历集合 // HashMap<String, HashMap<String, String>> xxgc Set<String> xxgcKeys=xxgc.keySet(); for(String xxgcKey:xxgcKeys){ System.out.println(xxgcKey); HashMap<String, String> xxgcValue=xxgc.get(xxgcKey); Set<String> bjKeys=xxgcValue.keySet(); for(String bjKey:bjKeys){ String bjValue=xxgcValue.get(bjKey); System.out.println("\t"+bjKey+"***"+bjValue); } } } }运行结果如下:
2、HashMap内嵌套ArrayList集合
/** * 案例:遍历以下信息: * 信息工程系(xxgc): * 20120581 通信工程专业 * 20120591 软件工程专业 *通信工程专业 : * s1(01 zhangsan) * s2(02 lisi) * 软件工程专业: * s3(01 wangwu) * s4(02 zhaoliu) * 思路:1、定义一个HashMap集合,String做键,ArrayList做值。 * 2、往集合中添加元素 * 3、用增强for遍历输出 */ public class HashMapDemo3 { public static void main(String[] args) { // 创建集合对象 HashMap<String, ArrayList<Student1>> hm=new HashMap<String, ArrayList<Student1>>(); //往ArrayList中添加学生对象 ArrayList<Student1> tx= new ArrayList<Student1>(); Student1 s1=new Student1("01","zhangsan"); Student1 s2=new Student1("02","lisi"); tx.add(s1); tx.add(s2); hm.put("tx",tx); ArrayList<Student1> rj= new ArrayList<Student1>(); Student1 s3=new Student1("01","wangwu"); Student1 s4=new Student1("02","zhaoliu"); rj.add(s3); rj.add(s4); hm.put("rj", rj); //遍历 Set<String> set=hm.keySet(); for(String key:set){ System.out.println(key); ArrayList<Student1> array=hm.get(key); for(Student1 s:array){ System.out.println("\t"+s.getSid()+"***"+s.getName()); } } } }所有集合的总结:
1:集合体系(掌握)
集合
|--Collection(单列)
|--List(有序,可重复)
|--ArrayList
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高。
|--Vector
底层数据结构是数组,查询快,增删慢。
线程安全,效率低。
|--LinkedList
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高。
|--Set(无序,唯一)
|--HashSet
底层数据结构是哈希表。
线程不安全,效率高。
怎么保证唯一性的呢?
它依赖两个方法:hashCode()和equals()
顺序:
首先判断hashCode()值是否相同。
同:继续走equals(),看返回值
如果true:就不添加到集合。
如果false:就添加到集合。
不同:就添加到集合。
|--TreeSet
底层数据结构是二叉树。
线程不安全,效率高。
怎么保证唯一性的呢? 是根据返回是否是0。
怎么保证排序的呢? 两种方式:
1) 自然排序(元素具备比较性)
实现Comparable接口
2)比较器排序(集合具备比较性)
实现Comparator接口
|--Map(双列 底层结构是针对键有效,跟值无关)
|--HashMap
底层数据结构是哈希表。
线程不安全,效率高。
怎么保证唯一性的呢?
它依赖两个方法:hashCode()和equals()
顺序:
首先判断hashCode()值是否相同。
同:继续走equals(),看返回值
如果true:就不添加到集合。
如果false:就添加到集合。
不同:就添加到集合。
|--Hashtable
底层数据结构是哈希表。
线程安全,效率低。
怎么保证唯一性的呢?
它依赖两个方法:hashCode()和equals()
顺序:
首先判断hashCode()值是否相同。
同:继续走equals(),看返回值
如果true:就不添加到集合。
如果false:就添加到集合。
不同:就添加到集合。
|--TreeMap
底层数据结构是二叉树。
线程不安全,效率高。
怎么保证唯一性的呢?
是根据返回是否是0。
怎么保证排序的呢?两种方式
自然排序(元素具备比较性)
实现Comparable接口
比较器排序(集合具备比较性)
实现Comparator接口
2:应用。(添加功能,判断功能,删除功能,获取功能,长度功能)
Collection
add(Object obj)
remove(Object obj)
contains(Object obj)
iterator()
size()
|--List
get(int index)
add(int index,Object obj)
remove(int index)
set(int index,Object obj)
|--Set
Map
put(Object key,Object value)
remove(Object key)
containsKey(Object key)
containsValue(Object value)
size()
get(Object key)
keySet()
values()
3:遍历方式
List:
迭代器(在源码中可以看到的,开发中也经常看到)
增强for(开发中看到,JDK5以后用)
普通for
如果仅仅为了遍历,用任意一种即可。一般选择前两种的任意一种。
如果要做修改,或者删除指定位置的元素,或者在指定位置添加元素。用普通for。
Set:
迭代器
增强for
任选一种。
Map:
键找值。
4:代码补齐:请对array,hs,hm进行遍历。
A: ArrayList<String> array = new ArrayList<String>();
方式1:
Iterator<String> it = array.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
方式2:
for(String s : array){
System.out.println(s);
}
方式3:
for(int x=0; x<array.size(); x++){
String s = array.get(x);
System.out.println(s);
}
B:HashSet<String> hs = new HashSet<String>();
方式1:
Iterator<String> it = hs.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
方式2:
for(String s : hs)
{
System.out.println(s);
}
C: HashMap<String,Strting> hm = new HashMap<String,String>();
Set<String> set = hm.keySet();
for(String key : set)
{
String value = hm.get(key);
System.out.println(key+"***"+value);
}
5:什么时候用谁?
是否键值对?
是:Map
是否对键排序?
是:TreeMap
否:HashMap
不懂的情况下,使用HashMap。
否:Collection
是否唯一
是:Set
是否对元素进行排序?
是:TreeSet
否:HashSet
不懂的情况下,使用HashSet
否:List
是否要安全:
是:Vector(真正开发中也不用)
List list = Collections.synchronizedList(new ArrayList());
否:ArrayList,LinkedList
查询多:ArrayList
增删多:LinkedList
不懂的情况下,使用ArrayList
有不对的地方希望大家给我指正出来,谢谢!! 谢谢浏览~~
------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
相关文章推荐
- 秒杀多线程第一篇——多线程笔试面试题汇总
- 黑马程序员--Java基础学习(IO流及字符编码)第二十一天
- 黑马程序员--Java基础学习(IO流--File对象和Properties)第二十天
- 【黑马程序员】重写构造方法实现两种功能
- iOS开发工程师面试知识点汇总
- 【黑马程序员】autorelease用法
- 黑马程序员-------Java笔记--------怎么越过泛型检查
- 【剑指offer】面试题39:深度二叉树
- 黑马程序员----集合框架的的基本操作
- iOS单例模式(面试必考)
- 黑马程序员-------Java笔记--------分数基本运算
- 黑马程序员----Java集合框架学习笔记2 Map-工具类-泛型
- 珍藏文:花10钟看一看少走30年弯路
- 黑马程序员——JAVA基础之面向对象(下)
- 程序员一生必读的书
- 幽默趣味:程序员如同妓女
- 黑马程序员-------Java笔记--------完数与质数
- 剑指Offer面试题:8.斐波那契数列
- 黑马程序员----Java集合框架学习笔记1-List 与Set
- 初入职场感悟