1.HashMap/**
* @author erqing
*
*/
public class MapTest {
public static void main(String[] args) {
/* 初始化map */
Map<String, Integer> map = new HashMap<String, Integer>();
System.out.println("HashMap的初始值:" + map.size());
System.out.println("HashMap是否为空:" + (map.isEmpty() ? "是" : "<span style="font-family: Arial, Helvetica, sans-serif;">否")); </span>
/* 想map中添加元素 */
map.put("erqing", 1);
map.put("niuniu", 2);
map.put("egg", 3);
System.out.println(map.size());
;
System.out.println("HashMap是否为空:" + (map.isEmpty() ? "是" : "否"));
/* 遍历HashMap中的元素 */
Set<String> set = map.keySet();
for (String s : set) {
System.out.println(s + " " + map.get(s) + " " + "hashcode:"
+ s.hashCode());
}
/*检测是否含有某个Key*/
System.out.println(map.containsKey("egg"));
/*检测是否含有某个Value*/
System.out.println(map.containsValue(2));
/*打印hashCode*/
System.out.println(map.hashCode());
}
}
- /**
- * 打印在数组中出现n/2以上的元素
- * 利用一个HashMap来存放数组元素及出现的次数
- * @author erqing
- *
- */
- public class HashMapTest {
- public static void main(String[] args) {
- int [] a = {2,3,2,2,1,4,2,2,2,7,9,6,2,2,3,1,0};
- Map<Integer, Integer> map = new HashMap<Integer,Integer>();
- for(int i=0; i<a.length; i++){
- if(map.containsKey(a[i])){
- int tmp = map.get(a[i]);
- tmp+=1;
- map.put(a[i], tmp);
- }else{
- map.put(a[i], 1);
- }
- }
- Set<Integer> set = map.keySet();
- for (Integer s : set) {
- if(map.get(s)>=a.length/2){
- System.out.println(s);
- }
- }
- }
- }
- /**
- *
- * 关于ArrayList的基本操作
- * 其它操作感兴趣的读者可以自己结合源码实现一下
- * * @author erqing
- *
- */
- public class ListTest {
- public static void main(String[] args) {
- /* 新建一个ArrayList */
- ArrayList<String> list = new ArrayList<String>();
- System.out.println("初始化大小:" + list.size());
- /* 添加元素 */
- list.add("zzz");
- list.add("egg");
- list.add("hell");
- list.add("child");
- System.out.println("当前容量:" + list.size());
- /* 将ArrayList的大小和实际所含元素的大小设置一致 */
- list.trimToSize();
- /* 遍历 */
- for (String string : list) {
- System.out.println(string);
- }
- /* 在指定位置插入元素 */
- list.add(2, "zhu");
- for (String string : list) {
- System.out.println(string);
- }
- System.out.println("--------------");
- /* 清空list */
- list.clear();
- /* 遍历 */
- for (String string : list) {
- System.out.println(string);
- }
- System.out.println("--------------");
- }
- }
- public class LinkedListTest {
- public static void main(String[] args) {
- /* 新建一个list */
- LinkedList<Integer> list = new LinkedList<Integer>();
- System.out.println(list.size());
- /* 向list中添加元素 */
- list.add(222);
- list.add(111);
- list.add(0);
- list.add(3333);
- list.add(8888);
- System.out.println(list.size());
- /* 遍历list */
- for (Integer integer : list) {
- System.out.println(integer);
- }
- /* 获取第一个元素 ,即header的next域*/
- System.out.println("第一个元素是:" + list.getFirst());
- /*获取最后一个元素,即header的previous域*/
- System.out.println("最后一个元素是:"+list.getLast());
- }
- }
理解该集合类之前,WeakHashMap多用于缓存系统,就是说在系统内存紧张的时候可随时进行GC,但是如果内存不紧张则可以用来存放一些缓存数
据。因为如果使用HashMap的话,它里面的值基本都是强引用,即使内存不足,它也不会进行GC,这样系统就会报异常
5.集合类面试
两种:一、总体介绍下集合类有哪些。这个问题只要把我上文中的图介绍一下就行了。二、比较一下XXX和XXXX。
1、HashMap和HashTable
相同点:二者都实现了Map接口,因此具有一系列Map接口提供的方法。
不同点:
1、HashMap继承了AbstractMap,而HashTable继承了Dictionary。
2、HashMap非线程安全,HashTable线程安全,到处都是synchronized关键字。
3、因为HashMap没有同步,所以处理起来效率较高。
4、HashMap键、值都允许为null,HashTable键、值都不允许有null。
5、HashTable使用Enumeration,HashMap使用Iterator。
推荐使用HashMap,因为她提供了比HashTable更多的方法,以及较高的效率,如果大家需要在多线程环境中使用,那么用Collections类来做一下同步即可2、Set接口和List接口
相同点:都实现了Collection接口
不同点:
1、Set接口不保证维护元素的顺序,而且元素不能重复。List接口维护元素的顺序,而且元素可以重复。
2、关于Set元素如何保证元素不重复,我将在下面的博文中给出。
3、ArrayList和LinkList
相同点:都实现了Collection接口
不同点:ArrayList基于数组,具有较高的查询速度,而LinkedList基于双向循环列表,具有较快的添加或者删除的速度,二者的区别,其实就是数组和列表的区别。
4、SortedSet和SortedMap
二者都提供了排序的功能。 来看一个小例子:
- public static void main(String[] args) {
- SortedMap<String, Integer> map = new TreeMap<String, Integer>();
- map.put("zgg", 1);
- map.put("erqing", 3);
- map.put("niu", 0);
- map.put("abc", 2);
- map.put("aaa", 5);
- Set<String> keySet = map.keySet();
- for (String string : keySet) {
- System.out.print(map.get(string)+" ");
- }
- }
输出:5 2 3 0 1
从结果看得出:SortedMap具有自动排序功能
5、TreeMap和HashMap
HashMap具有较高的速度(查询),TreeMap则提供了按照键进行排序的功能。
6、HashSet和LinkedHashSet
HashSet,为快速查找而设计的Set。存入HashSet的对象必须实现hashCode()和equals()。
LinkedHashSet,具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序),于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。
7、TreeSet和HashSet
TreeSet: 提供排序功能的Set,底层为树结构 。相比较HashSet其查询速度低,如果只是进行元素的查询,我们一般使用HashSet。
8、ArrayList和Vector
同步性:Vector是线程安全的,也就是说是同步的,而ArrayList是线程序不安全的,不是同步的。
数据增长:当需要增长时,Vector默认增长为原来一培,而ArrayList却是原来的一半
9、Collection和Collections
Collection是一系列单值集合类的父接口,提供了基本的一些方法,而Collections则是一系列算法的集合。里面的属性和方法基本都是static的,也就是说我们不需要实例化,直接可以使用类名来调用。
6.常见问题
1、Set集合如何保证对象不重复
这儿我采用HashSet来实现Set接口,先看个例子:
- public static void main(String[] args) {
- Set<String> set = new HashSet<String>();
- String a = "hello";
- String b = "hello";
- String s = new String("hello");
- String s1 = new String("hello");
- set.add(a);
- set.add(s);
- set.add(s1);
- set.add(b);
- System.out.println("size:"+set.size());
- for (String ss : set) {
- System.out.println(ss);
- }
- }
输出:
size:1
hello
说明,Set集合不允许有重复出现的对象,且最终的判断是根据equals()的。其实原理是这样的:HashSet的底层采用HashMap来存放数据,HashMap的put()方法是这样的:
- public V put(K key, V value) {
- if (key == null)
- return putForNullKey(value);
- int hash = hash(key.hashCode());//----------1----------
- int i = indexFor(hash, table.length);//-----------2---------
- for (Entry<K,V> e = table[i]; e != null; e = e.next) {//-----------3---------
- Object k;
- if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
- V oldValue = e.value;
- e.value = value;
- e.recordAccess(this);
- return oldValue;
- }
- }//------------------4--------------------
- modCount++;
- addEntry(hash, key, value, i);
- return null;
- }
当向HashMap中添加元素的时候,首先计算元素的hashcode值,然后根据1处的代码计算出Hashcode的值,再根据2处的代码计算出这个元素的存储位置,如果这个位置为空,就将元素添加进去;如果不为空,则看3-4的代码,遍历索引为i的链上的元素,如果key重复,则替换并返回oldValue值
2、集合类排序问题
一种情况是集合类本身自带排序功能,如前面说过的TreeSet、SortedSet、SortedMap等,另一种就是本身不带排序功能,我们通过为需要排序的类实现Comparable或者Comparator接口来实现。
先来看两个例子,一个是实现Comparable的,一个是实现Comparator的,为了方便,我将类都写在了一个文件中。
- package com.xtfggef.list.test;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collections;
- import java.util.List;
- @SuppressWarnings("unchecked")
- public class ComparableTest {
- public static void main(String[] args) {
- // User[] users = { new User("egg", 23), new User("niuniu", 22),
- // new User("qing", 28) };
- // Arrays.sort(users);
- // for (User user : users) {
- // System.out.println(user.getName() + " " + user.getAge());
- // }
- List<User> users = new ArrayList<User>();
- users.add(new User("egg", 23));
- users.add(new User("niu", 22));
- users.add(new User("qing", 28));
- Collections.sort(users);
- for (User user : users) {
- System.out.println(user.getName() + " " + user.getAge());
- }
- }
- }
- @SuppressWarnings("unchecked")
- class User implements Comparable {
- private String name;
- private int age;
- public User(String name, int age) {
- super();
- 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(Object o) {
- return this.age - ((User) o).getAge();
- }
- }
- package com.xtfggef.comparator.test;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Comparator;
- import java.util.List;
- public class ComparatorTest {
- public static void main(String[] args) {
- List<User> users = new ArrayList<User>();
- users.add(new User("egg", 21));
- users.add(new User("niu", 22));
- users.add(new User("gg", 29));
- UserComparator comparator = new UserComparator();
- Collections.sort(users, comparator);
- for (User user : users) {
- System.out.println(user.getUsername() + " " + user.getAge());
- }
- }
- }
- class User {
- private String username;
- private int age;
- public User(String username, int age) {
- super();
- this.username = username;
- this.age = age;
- }
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- }
- class UserComparator implements Comparator<User> {
- @Override
- public int compare(User user1, User user2) {
- int age1 = user1.getAge();
- int age2 = user2.getAge();
- if (age1 < age2) {
- return 1;
- }
- return 0;
- }
- }
总结为:
相同点:
1、二者都可以实现对象的排序,不论用Arrays的方法还是用Collections的sort()方法。
不同点:
1、实现Comparable接口的类,似乎是预先知道该类将要进行排序,需要排序的类实现Comparable接口,是一种“静态绑定排序”。
2、实现Comparator的类不需要,设计者无需事先为需要排序的类实现任何接口。
3、Comparator接口里有两个抽象方法compare()和equals(),而Comparable接口里只有一个方法:compareTo()。
4、Comparator接口无需改变排序类的内部,也就是说实现算法和数据分离,是一个良好的设计,是一种“动态绑定排序”。
5、Comparator接口可以使用多种排序标准,比如升序、降序等。
3、使用for循环删除元素陷阱
先来看看下面这个程序:
- public class Test {
- public static void main(String[] args) {
- List<String> list = new LinkedList<String>();
- list.add("A");
- list.add("B");
- list.add("C");
- for(int i=0; i<list.size(); i++){
- list.remove(i);
- }
- for(String item:list){
- System.out.println(item);
- }
- }
- }
解决办法:
-
public class Test {
public static void main(String[] args) {
List<String> list = new LinkedList<String>();
list.add("A");
list.add("B");
list.add("C");
for(int i=0; i<list.size(); i++){
list.remove(i);
i -= 1;//每次删除完后,i减少1
}
for(String item:list){
System.out.println(item);
}
}
}
7.集合的关系
下面的表格也许可以更直接的表现出他们之间的区别和联系:
接口 |
简述 |
实现 |
操作特性 |
成员要求 |
Set |
成员不能重复 |
HashSet |
外部无序地遍历成员 |
成员可为任意Object子类的对象,但如果覆盖了equals方法,同时注意修改hashCode方法。 |
TreeSet |
外部有序地遍历成员;附加实现了SortedSet, 支持子集等要求顺序的操作 |
成员要求实现caparable接口,或者使用 Comparator构造TreeSet。成员一般为同一类型。 |
||
LinkedHashSet |
外部按成员的插入顺序遍历成员 |
成员与HashSet成员类似 |
||
List |
提供基于索引的对成员的随机访问 |
ArrayList |
提供快速的基于索引的成员访问,对尾部成员的增加和删除支持较好 |
成员可为任意Object子类的对象 |
LinkedList |
对列表中任何位置的成员的增加和删除支持较好,但对基于索引的成员访问支持性能较差 |
成员可为任意Object子类的对象 |
||
Map |
保存键值对成员,基于键找值操作,compareTo或compare方法对键排序 |
HashMap |
能满足用户对Map的通用需求 |
键成员可为任意Object子类的对象,但如果覆盖了equals方法,同时注意修改hashCode方法。 |
TreeMap |
支持对键有序地遍历,使用时建议先用HashMap增加和删除成员,最后从HashMap生成TreeMap;附加实现了SortedMap接口,支持子Map等要求顺序的操作 |
键成员要求实现caparable接口,或者使用Comparator构造TreeMap。键成员一般为同一类型。 |
||
LinkedHashMap |
保留键的插入顺序,用equals 方法检查键和值的相等性 |
成员可为任意Object子类的对象,但如果覆盖了equals方法,同时注意修改hashCode方法。 |
||
IdentityHashMap |
使用== 来检查键和值的相等性。 |
成员使用的是严格相等 |
||
WeakHashMap |
其行为依赖于垃圾回收线程,没有绝对理由则少用 |
|
实现Collection接口的类,如Set和List,他们都是单值元素(其实Set内部也是采用的是Map来实现的,只是键值一样,从表面理解,就是单值),不像实现Map接口的类一样,里面存放的是key-value(键值对)形式的数据。这方面就造成他们很多的不同点,如遍历方式,前者只能采用迭代或者循环来取出值,但是后者可以使用键来获得值得值。