您的位置:首页 > 职场人生

黑马程序员—————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存储字符串并遍历

/* 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>、期待与您交流! -------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: