个人小结:本篇主要介绍Map集合和泛型。Map 集合类用于存储元素对(称作“键”和“值”),其中每个键映射到一个值。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。具体有泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。
一、Map集合
Map集合: 该集合存储键值对,一对一对往里存,而且要保证键的唯一性。
常用方法:
1、添加
put(K key, V value)
putAll(Map<? extends K,? extends V> m)
2、删除
clear()
remove(Object key)
3、判断
containsKey(Object key)
containsValue(Object value)
isEmpty()
4、获取
get(Object key)
size()
values()
entrySet()
keySet()
常用的实现类:
1、添加
put(K key, V value)
putAll(Map<? extends K,? extends V> m)
2、删除
clear()
remove(Object key)
3、判断
containsKey(Object key)
containsValue(Object value)
isEmpty()
4、获取
get(Object key)
size()
values()
entrySet()
keySet()
常用的实现类:
Map--
|--Hashtable :底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。jkd 1.0,效率低
|--HashMap:底层是哈希表数据结构,可以存入null键null值,该集合是不同步的。jdk 1.2,效率高。
|--TreeMap:底层是二叉树数据结构,线程不同步,可以用于给map集合中的键进行排序。
和Set很像,其实,Set集合底层就是使用了Map集合。
|--Hashtable :底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。jkd 1.0,效率低
|--HashMap:底层是哈希表数据结构,可以存入null键null值,该集合是不同步的。jdk 1.2,效率高。
|--TreeMap:底层是二叉树数据结构,线程不同步,可以用于给map集合中的键进行排序。
和Set很像,其实,Set集合底层就是使用了Map集合。
示例:
import java.util.*;
class MapDemo
{
public static void main(String[] args)
{
Map<String,String> map = new HashMap<String,String>();
//添加元素,如果添加时出现相同的键,那么后添加的值会覆盖并返回原有键对应的值,
System.out.println("put:"+map.put("01","zhangsan1"));
System.out.println("put:"+map.put("01","wangwu1"));
map.put("02","zhangsan2");
map.put("03","zhangsan3");
map.put(null,"haha"); //若是 Hashtable 存null,则抛出NullPointerException
System.out.println("containsKey:"+map.containsKey("02"));
//System.out.println("remove:"+map.remove("02"));
System.out.println("get:"+map.get("02"));
System.out.println("get:"+map.get(null));
//可以通过get方法的返回值来判断一个键是否存在。通过返回null来判断。
//获取map集合中所有的值。
Collection <String> coll = map.values();
System.out.println(coll);
System.out.println("map:"+map);
}
}
二、Map集合的两种取出方式
1、Set<K> keySet : 将Map中所有的键存入到Set集合,因为Set具备迭代器。所以可以用迭代方式取出所有的键,再根据get方法,获取每一个键对应的值。 Map集合的取出原理:将Map集合转换成Set集合,在通过迭代器取出。
2、Set<Map.Entry<k,v>> entrySet: 将Map集合中的映射关系存入到了Set集合中,而这个关系的数据类型就是:Map.Entry
示例:
import java.util.*;
class MapDemo2
{
public static void main(String[] args)
{
Map<String,String> map = new HashMap<String,String>();
map.put("02","zhangsan2");
map.put("03","zhangsan3");
map.put("01","zhangsan1");
map.put("04","zhangsan4");
//将Map集合中的映射关系取出,存入到Set集合中。
Set<Map.Entry<String,String>> entrySet = map.entrySet();
Iterator<Map.Entry<String,String>> it = entrySet.iterator();
while (it.hasNext())
{
Map.Entry<String,String> me = it.next();
String key = me.getKey();
String value = me.getValue();
System.out.println(key+":"+value);
}
/*
//先获取map集合的所有键的Set集合,keySet();
Set<String> keySet = map.keySet();
//有了Set集合,就可以获取其迭代器。
Iterator<String> it = keySet.iterator();
while (it.hasNext())
{
String key = it.next();
//有了键就可以通过Map集合的get方法获取其对于的值。
String value = map.get(key);
System.out.println("key:"+key+"...value:"+value);
}
*/
}
}
/*
Map.Entry 其实Entry也是一个接口,他是Map接口中的一个内部接口。
*/
练习
/*
需求:
每一个学生都有对应的归属地,学生Student,地址String.
学生属性:姓名,年龄。
注意:姓名和年龄相同的视为同一个学生。保证学生的唯一性。
步骤:
1、描述学生。
2、定义map容器,将学生作为键,地址作为值,存入。
3,获取map集合中的元素。
*/
import java.util.*;
class MapTest
{
public static void main(String[] args)
{
Map<Student,String> map = new HashMap<Student,String>();
map.put(new Student("lisi01",18),"安徽");
map.put(new Student("lisi02",19),"广东");
map.put(new Student("lisi03",20),"安徽");
map.put(new Student("lisi04",23),"广东");
map.put(new Student("lisi04",23),"广西");
//第一种取出方式 :KeySet
System.out.println("*********第一种取出方式 :KeySet*********");
Set<Student> keySet = map.keySet();
Iterator<Student> it = keySet.iterator();
while (it.hasNext())
{
Student s = it.next();
String add = map.get(s);
System.out.println(s.getName()+"..."+s.getAge()+"岁,来自"+add);
}
//第二种取出方式 :EntrySet
System.out.println("*********第二种取出方式 :EntrySet*********");
Set<Map.Entry<Student,String>> entrySet = map.entrySet();
Iterator<Map.Entry<Student,String>> it2 = entrySet.iterator();
while (it2.hasNext())
{
Map.Entry<Student,String> me = it2.next();
Student s = me.getKey();
String name = s.getName();
int age = s.getAge();
String add = me.getValue();
System.out.println(name+"..."+age+"岁,来自"+add);
}
}
}
//定义学生类,并实现Comparable接口
class Student implements Comparable<Student>
{
private String name;
private int age;
public 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;
}
//复写hashCode方法
public int hashCode()
{
return name.hashCode()+age*34;
}
//复写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 getName()
{
return name;
}
public int getAge()
{
return age;
}
}
/*
为什么这里用比较器就不行,因为不是 TreeMap !,一般带Tree的才有比较器
class Comp implements Comparator<Student>
{
public int compare(Student s1,Student s2)
{
int num = s1.getName().compareTo(s2.getName());
if (num==0)
return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
return num;
}
}
*/
练习
/*
需求:对学生对象的年龄进行升序排序。
因为数据是以键值对形式存在的。所以要使用可以排序的Map集合,TreeMap.
*/
import java.util.*;
class MapTest2
{
public static void main(String[] args)
{
TreeMap<Student,String> tm = new TreeMap<Student,String>(new StuNameComp());
tm.put(new Student("tlisi01",34),"安徽");
tm.put(new Student("clisi02",19),"广东");
tm.put(new Student("blisi03",20),"安徽");
tm.put(new Student("hlisi04",23),"广东");
tm.put(new Student("hlisi04",23),"广西");
Set<Map.Entry<Student,String>> entrySet = tm.entrySet();
Iterator<Map.Entry<Student,String>> it = entrySet.iterator();
while (it.hasNext())
{
Map.Entry<Student,String> me = it.next();
Student s = me.getKey();
String add = me.getValue();
System.out.println(s.getName()+":"+s.getAge()+"岁,来自:"+add);
}
}
}
//定义比较器
class StuNameComp implements Comparator<Student>
{
public int compare(Student s1,Student s2)
{
int num = s1.getName().compareTo(s2.getName());
if (num==0)
return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
return num;
}
}
练习
/*
练习需求:
"sdfgzxcvasdfxcvdf"获取该字符串中的字母出现的次数。希望打印结果:a(1)c(2)....
分析:通过结果发现,每一个字母都有对应的次数说明字母和次数之间都有映射关系。
注意了,当发现有映射关系时,可以选择Map集合。因为Map集合中存放的就是映射关系。
什么时候使用Map集合呢?当数据之间存在这种映射关系时,就应先想到Map集合。
思路:
1、将字符串转换成字符数组,因为要对每一个字母进行操作
2、定义一个Map集合,因为打印结果有字母顺序,所以使用TreeMap集合
3、遍历字符数组,将每一个字母作为键去查Map集合
如果返回null,将该字母和1存入到Map集合中
如果返回不是null,说明该字母在Map集合已经存在并有对应次数
那么就获取该次数并进行自增,然后将该字母和自增后的次数存入到Map集合中,
覆盖掉原来键所对应的值
4、将Map集合中的数据变成指定的字符串形式返回。
*/
import java.util.*;
class MapTest3
{
public static void main(String[] args)
{
String str = "sdfgz+xcv-asd9fxcvdf";
char[] cha = str.toCharArray();
TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();
for (int x = 0;x<cha.length ; x++)
{
/*自己方法
if (!tm.containsKey(cha[x]))
{
tm.put(cha[x],1);
}
else
{
int y = tm.get(cha[x]).intValue();
y++;
tm.put(cha[x],y);
}
*/
/*视频方法1
Integer value = tm.get(cha[x]);
if(value==null)
{
tm.put(cha[x],1);
}
else
{
value = value +1;
tm.put(cha[x],value);
}
*/
//视频方法2
if(!(cha[x]>='a' && cha[x]<='z'|| cha[x]>='A' && cha[x]<='Z'))
continue;
int count = 0;
Integer value = tm.get(cha[x]);
if (value!=null)
count = value;
count++;
tm.put(cha[x],count);
System.out.println(tm);
}
Set<Map.Entry<Character,Integer>> entrySet = tm.entrySet();
Iterator<Map.Entry<Character,Integer>> it = entrySet.iterator();
while (it.hasNext())
{
Map.Entry<Character,Integer> s = it.next();
Character key = s.getKey();
Integer value = s.getValue();
System.out.print(key+"("+value+")");
}
}
/*
public static String charCount(String str)
{
char[] cha = str.toArrayChar();
}
*/
}
三、Map扩展
map集合被使用是因为具备映射关系。
"yuereban" "01" "zhangsan";
"yureban" "02" "lisi";
"jiuyeban" "01" "wangwu";
"jiuyeban" "02" "zhaoliu";
一个学校有多个教室,每个教室都有名称。
"yuereban" "01" "zhangsan";
"yureban" "02" "lisi";
"jiuyeban" "01" "wangwu";
"jiuyeban" "02" "zhaoliu";
一个学校有多个教室,每个教室都有名称。
第一种方式:嵌套集合,大集合里套小集合,小集合当作大集合的一个元素。
第二种方式: 把后两个信息堪称一个学生对象。
"yureban" Student("01" , "zhangsan");
示例:
第二种方式: 把后两个信息堪称一个学生对象。
"yureban" Student("01" , "zhangsan");
示例:
import java.util.*;
//第一种方式:嵌套集合
class MapDemo3
{
public static void main(String[] args)
{
//System.out.println("Hello World!");
HashMap<String,HashMap<String,String>> czbk = new HashMap<String,HashMap<String,String>>();
HashMap<String,String> yure = new HashMap<String,String>();
HashMap<String,String> jiuye = new HashMap<String,String>();
czbk.put("yureban",yure);
czbk.put("jiuyeban",jiuye);
yure.put("01" , "zhangsan");
yure.put("02" , "lisi");
jiuye.put("01" , "wangwu");
jiuye.put("02" , "zhaoliu");
jiuye.put("03" , "zhengqi");
Set<String> keySet = czbk.keySet();
Iterator<String> it = keySet.iterator();
while (it.hasNext())
{
String jiaoshi = it.next();
HashMap<String,String> hm = czbk.get(jiaoshi);
System.out.println(jiaoshi);
getAllInfo(hm);
}
}
public static void getAllInfo(HashMap<String,String> hm)
{
Set<String> keySet = hm.keySet();
Iterator<String> it = keySet.iterator();
while (it.hasNext())
{
String id = it.next();
String name = hm.get(id);
System.out.println(id+":"+name);
}
}
}
//第二种方式:封装学生类
class MapDemo3
{
public static void main(String[] args)
{
HashMap<String,List<Student>> czbk = new HashMap<String,List<Student>>();
List<Student> yure = new ArrayList<Student>();
List<Student> jiuye = new ArrayList<Student>();
czbk.put("yureban",yure);
czbk.put("jiuyeban",jiuye);
yure.add(new Student("01","zhangsan"));
yure.add(new Student("02","lisi"));
yure.add(new Student("03","lisi2"));
jiuye.add(new Student("01" , "wangwu"));
jiuye.add(new Student("02" , "zhaoliu"));
jiuye.add(new Student("03" , "zhengqi"));
Set<String> keySet = czbk.keySet();
Iterator<String> it = keySet.iterator();
while (it.hasNext())
{
String jiaoshi = it.next();
List<Student> li = czbk.get(jiaoshi);
System.out.println(jiaoshi);
getAllInfo(li);
}
}
public static void getAllInfo(List<Student> li)
{
Iterator<Student> it = li.iterator();
while (it.hasNext())
{
Student stu = it.next();
System.out.println(stu.toString());
}
}
}
class Student
{
private String id;
private String name;
public Student(String id,String name)
{
this.id = id;
this.name = name;
}
public String toString()
{
return id+":"+name;
}
}
四、泛型
泛型:jdk1.5版本后出现的新特性,用于解决安全问题,是一个类型安全机制。
好处:
1、将运行时出现的问题ClassCastException,转移到了编译时期,方便于程序员解决问题,让运行时期问题减少,安全。
2、避免了强制转换的麻烦。
泛型格式:通过<>来定义要操作的引用数据类型。
在使用java提供的对象时,什么时候写泛型呢?
通常在集合框架中很常见。只要见到<>就要定义泛型。其实<>就是用来接收类型的。
当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
好处:
1、将运行时出现的问题ClassCastException,转移到了编译时期,方便于程序员解决问题,让运行时期问题减少,安全。
2、避免了强制转换的麻烦。
泛型格式:通过<>来定义要操作的引用数据类型。
在使用java提供的对象时,什么时候写泛型呢?
通常在集合框架中很常见。只要见到<>就要定义泛型。其实<>就是用来接收类型的。
当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
示例:
class Worker
{
}
class Student
{
}
/*
class Tool
{
private Worker w;
public void setWorker(Worker w)
{
this.w= w;
}
public Worker getWorker()
{
return w;
}
}
*/
//泛型前做法
class Tool
{
private Object obj;
public void setObject(Object obj)
{
this.obj= obj;
}
public Object getObject()
{
return obj;
}
}
//泛型类
/*
什么时候定义泛型类?
当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展,现在定义泛型来完成扩展。
*/
class Utils<QQ>
{
private QQ q;
public void setObject(QQ q)
{
this.q = q;
}
public QQ getObject()
{
return q;
}
}
class GenericDemo3
{
public static void main(String[] args)
{
/*
Tool t = new Tool();
t.setObject(new Student());
Worker w = (Worker)t.getObject();
*/
Utils<Worker> u = new Utils<Worker>();
u.setObject(new Student());
Worker w = u.getObject();
}
}
示例:
/*
class Demo<T>
{
public void show(T t)
{
System.out.println("show:"+t);
}
public void print(T t)
{
System.out.println("print:"+t);
}
}
*/
/*
泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。
为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。
*/
/*
特殊之处:
静态方法不可以访问类上定义的泛型。
如果静态方法操作的引用数据类型不确定,可以将泛型定义在方法上。
*/
class Demo<T>
{
public void show(T t)
{
System.out.println("show:"+t);
}
public <Q> void print(Q q)
{
System.out.println("print:"+q);
}
public static <S> void method(S s)
{
System.out.println("method:"+s);
}
}
class GenericDemo4
{
public static void main(String[] args)
{
/*
Demo<Integer> d = new Demo<Integer>();
d.show(new Integer(4));
//d.print("haha");
Demo<String> d1 = new Demo<String>();
d1.print("haha");
//d1.show(5);
*/
/*
Demo d = new Demo();
d.show("haha");
d.show(new Integer(4));
d.print(5);
*/
Demo<String> d = new Demo<String>();
d.show("haha");
//d.show(4);
d.print(5);
d.print("hehe");
d.method("hhahahahah");
}
}
五、泛型的限定
? 通配符,也可以理解为占位符
? extends E;可以接收E类型或者E的子类型。————上限
如:ArrayList<? extends Number>x = new ArrayList<Integer>();
? super E:可以接收E类型或者E的父类型,—————下限
? super E:可以接收E类型或者E的父类型,—————下限
如:ArrayList<? super Integer>x = new ArrayList<Number>();
示例:
import java.util.*;
class GenericDemo6
{
public static void main(String[] args)
{
/*
ArrayList<String> al = new ArrayList<String>();
al.add("abc1");
al.add("abc2");
al.add("abc3");
ArrayList<Integer> al1 = new ArrayList<Integer>();
al1.add(4);
al1.add(7);
al1.add(1);
printColl(al);
printColl(al1);
*/
ArrayList<Person> al = new ArrayList<Person>();
al.add(new Person("abc1"));
al.add(new Person("abc2"));
al.add(new Person("abc3"));
//printColl(al);
ArrayList<Student> al1 = new ArrayList<Student>();
al1.add(new Student("abc1"));
al1.add(new Student("abc8"));
al1.add(new Student("abc9"));
printColl(al1); //ArrayLis<Person> al = new ArrayList<Student>(); --error!
}
public static void printColl(ArrayList<? extends Person> al)
{
Iterator<? extends Person> it = al.iterator();
while (it.hasNext())
{
System.out.println(it.next().getName());
}
}
/*
public static void printColl(ArrayList<?>/*<String> al)//ArrayList<String> al = new ArrayList<Integer>(); ---error!
{
Iterator<?>/*<String>it = al.iterator();
while (it.hasNext())
{
System.out.println(it.next());
}
}
*/
}
class Person
{
private String name;
Person(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
class Student extends Person
{
Student(String name)
{
super(name);
}
}
class Student implements Comparable<Student>//<? super E>
{
public int compareTo()(Student s)
{
this.getName();
}
}
class Comp implements Comparator<Person>
{
public int compare(Person s1,Person s2)
{
Person s1 = new Student("abcd1");
return s1.getName().compareTo(s2.getName());
}
}
/*
TreeSet<Student> ts = new TreeSet<Student>(new Comp());
ts.add(new Student("abcd1"));
ts.add(new Student("abcd1"));
ts.add(new Student("abcd1"));*/