我是靠谱客的博主 高挑巨人,这篇文章主要介绍Java笔记(15)泛型与Map集合,现在分享给大家,希望可以做个参考。

Java笔记(15)泛型和Map集合

1.泛型

泛型在java中有着非常重要的地位,在面向对象设计及各种设计模式中有着重要的作用;泛型类似于方法中传递的参数,但不同于方法中的参数类型要明确指定,泛型可以在定义类、接口、方法时不必明确指定参数的类型,可以用诸如T、K、E等大写字母表示泛型,泛指所有的引用类型,直到外部创建其对象的时候再去明确指定其具体类型。

举一个常用的例子,在平常使用泛型最多的地方通常是集合,而集合的特性是能接收所有的引用类型,这时我们在定义集合时就难免遇到一个问题,到底该给集合指定具体接收哪种类型呢,显然除了Object类型可以代表任意类型外,其他的类型都不能满足这个要求。但如果用Object作为默认接收类型时,也会产生一个问题,例如在集合中,默认Object类型集合就能添加所有类型,这时集合添加两个String类型和一个Integer类型元素时都可以编译通过,但如果在获取这三个元素时就会出现问题,如果用String类型将所有Object类型接收,在把Integer类型的元素转为String时就会出现问题,而这个问题编译时是不会报错的,因为存储的时候Integer被转为了Object类型,所以将实际类型是Integer的Object类型的元素转为String在编译器看来是没有问题的,但运行时就会发生问题,这对程序而言显然是不安全的;于是,java就提供了泛型,它如同Object一样可以代表所有的引用类型,但在创建对象时你可以为其指定具体的类型,在刚才这个问题中就可以创建集合时明确将类型指定为String,这样集合在添加元素时就不能添加String类型外的类型,就避免了上面的问题;

(1) 泛型使用例子:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
//将泛型指定为String类型 ArrayList<String> list = new ArrayList<String>(); //这时的集合就只能添加String类型元素,添加其他类型编译器就会报错 list.add("a"); list.add("b"); //迭代器的类型也必须和集合返回的迭代器类型相同,否则编译器也会报错 Iterator<String> it = list.iterator(); while(it.hasNext()){ //这时用Integer强转就会编译器报错 Integer i = (Integer) it.next(); }

(2) 泛型类定义:

会使用泛型,还要会定义泛型;

复制代码
1
2
3
4
5
6
7
8
//这里的尖括号里可以起任意标识符,建议大写字母,多个泛型用逗号隔开,标识指定的泛型类型 public class Test<E> { } //泛型类在实例化时必须指定其具体类型,且不能是基本类型,可以是自定义的类 Test<String> test = new Test<String>(); //注意的是,泛型类不一定非要传入泛型类实参,可以是下面的形式,这种形式不会限定其接收的类型 Test test1 = new Test();

(3) 泛型接口定义

与泛型类的定义基本一致;

复制代码
1
2
public Interface Demo<T>{}

(4) 泛型方法定义

注意的是,在定义泛型方法时,泛型方法里面的泛型参数必须是类泛型里面定义过的,否则会报错,且只有声明了< T>的方法才可以称作泛型方法,单纯使用泛型成员不算泛型方法;

复制代码
1
2
3
4
5
6
7
8
9
10
11
public class MyTest<T> { private T t; public void set(T t){ this.t = t; } //get方法不算泛型方法,它只是使用了已经定义过的泛型成员 public T get() { return t; } }

(5) 泛型通配符

泛型通配符有三种:
<?> 表示Object和所有的java类
<? extends E> E及它的子类
<? super E> E及它的父类

泛型通配符可以用在泛型类、泛型接口、泛型方法定义上,也可以用在泛型类实例化的声明上,但实际创建的时候,即new的时候后面的泛型中不能使用通配符,且前面是具体类型时,则后面泛型的类型必须和前面的一致。

(6) JDK7新特性泛型推断
在JDK7以前,泛型类实例化需要这样:

复制代码
1
2
ArrayList<String> list = new ArrayList<String>();

而JDK7之后,泛型实例化可以这样:

复制代码
1
2
ArrayList<String> list = new ArrayList<>();

可以看到不用在后面保持和前面一样,因为编译器会自动根据前面的类型推断后面的类型,但平常开发中不建议这么做;

2.Map集合

Map集合也称为键值对集合,用于保存映射关系的数据,Map集合中保存了两组值,一组是Key,一组是Value,其中Key值是不能重复的;
Key和Value存在一一对应关系,通过Key能找到唯一的Value值;

复制代码
1
2
3
4
public interface Map<K,V> { // Query Operations }

Map集合中的Key可以看做是一个Set数组,而Value可以看做一个List数组。

下面列举一些Map接口中常用方法:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
clear():删除Map中所有的 key-value对 containsKey():是否包含指定的key containsValue(): 是否包含一个或多个value。 entrySet(): 返回包含的 key-value对组成的Set集合,每个集合元素都是Map.Entry对象, Entry是Map的内部类。 get():返回指定key对应的value。 isEmpty(): 是否为空 keySet(): 返回key组成的Set集合 put(): 添加一个key-value对,如果存在,覆盖以前的 putAll(): 指定Map中复制过来 remove():删除指定key,或 key-value。 size():返回键值对个数 values():返回所有 value组成的 Collection。

(1) HashMap
HashMap是实现了Map接口的实现类,允许Null键和值,但由于键的唯一性,只允许存在一个Null键,它是一个非同步、无顺序的键值对集合;

HashMap底层数据结构是红黑树,它的工作原理是:
首先在HashMap底层维护了一个数组,在添加一个key-value时先判断key的hash值,以此确定插入数组的位置,但是可能同一hash值的元素已经被放在该位置上了,这时就添加到同一hash值元素的后面,因此就形成了一个单向链表来解决hash冲突的问题。而当这个链表长度超过一定长度时,就将这个链表转为红黑树结构,即一种自平衡的二叉树,这样可以大大增加查找速度,因为链表的查找速度是很慢的;

HashMap的使用:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//创建HashMap集合 HashMap<String,String> hm = new HashMap<String,String>(); //存放元素 hm.put("0001","李四"); hm.put("0002","张三"); hm.put("0003","王二"); hm.put("0001","李麻花"); //遍历HashMap集合 Set<String> set = hm.keySet(); for(String key : set){ String value = hm.get(key); System.out.println(key+"---"+value); } //结果是 0002---张三 0003---王二 0001---李麻花 可以看到李四被覆盖了,这是由于put方法的源码里针对key值相同的就将value值覆盖

HashMap的方法大部分来自Map接口,详细请参考API;

(2) Hashtable
Hashtable是一个古老的基于哈希表实现Map接口的集合,它与HashMap使用基本相同,是线程安全但效率很低的Map集合,不允许null键和null值。不推荐使用这个集合,如果需要线程安全,建议使用Collections工具类将HashMap同步使用;

(3) LinkedHashMap
LinkedHashMap集合 是 HashMap集合的子类。它的特点是使用双向链表维护key-value键值对的次序,使其取出顺序和存入顺序一致;
它的使用方法和HashMap基本一致;

(4) TreeMap
TreeMap是基于红黑树的Map接口实现;它的特点是可以对键进行排序;
下面来一个使用排序的例子:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/* * 定义一个学生类,有姓名和分数两个属性 */ public class Student { private String name; private int grade; public Student(String name, int grade) { super(); this.name = name; this.grade = grade; } public Student() { super(); // TODO Auto-generated constructor stub } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getGrade() { return grade; } public void setGrade(int grade) { this.grade = grade; } } //测试TreeMap集合 public class MyTest { public static void main(String[] args) { // 创建TreeMap集合,并重写排序比较器 TreeMap<Student, String> map = new TreeMap<Student, String>(new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { // 按分数高低排序 int num1 = o2.getGrade() - o1.getGrade(); int num2 = num1 == 0 ? o2.getName().compareTo(o1.getName()) : num1; return num2; } }); // 创建6个Student对象 Student s1 = new Student("王一", 99); Student s2 = new Student("王二", 87); Student s3 = new Student("王三", 96); Student s4 = new Student("王四", 98); Student s5 = new Student("王五", 99); Student s6 = new Student("王五", 99); map.put(s1, "高一(2)班"); map.put(s2, "高一(1)班"); map.put(s3, "高一(3)班"); map.put(s4, "高一(2)班"); map.put(s5, "高一(8)班"); map.put(s6, "高一(2)班"); Set<Student> set = map.keySet(); for (Student s : set) { String str = map.get(s); System.out.println(s.getName() + "---" + s.getGrade() + "---" + str); } } } //结果 王一---99---高一(2)班 王五---99---高一(2)班 王四---98---高一(2)班 王三---96---高一(3)班 王二---87---高一(1)班 可以看出,TreeMap既有Map集合的特性key唯一且key相同时后面的覆盖前面的值,也有key排序的功能;

Map集合总结:
HashMap:键唯一,值可重复,允许null值与null键,但null键只能有一个,不保证存取和取出顺序一致,线程不安全,效率高;
Hashtable:键唯一,值可重复,不允许null键和值,不保证存取和取出顺序一致,线程安全,效率低;
LinkedHashMap: 键唯一,值重复,允许null键和值,null键唯一,保证了存储和取出去顺序一致,线程不安全,效率高;
TreeMap:键唯一,值重复,允许null键值,可以排序,默认自然排序,如果自己排序需要实现Comparator接口并实现compare方法,线程不安全,效率高。

使用场景:有键值对关系的数据使用Map集合,如果不需要排序使用HashMap,要安全使用Hashtable(不建议使用,可以用Collections工具类包装HashMap),要存取顺序一致使用LinkedHashMap,要排序使用TreeMap;

注意的是,集合可以嵌套集合,注意其中的数据关系即可;

最后

以上就是高挑巨人最近收集整理的关于Java笔记(15)泛型与Map集合的全部内容,更多相关Java笔记(15)泛型与Map集合内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(51)

评论列表共有 0 条评论

立即
投稿
返回
顶部