一、set集合
set集合不根据索引去获取元素,想遍历结合也不能依靠普通的for循环。
遍历集合只能使用迭代器,新循环可以遍历,因为新循环的实现机制也是使用迭代器。
set常用实现类:
HashSet:使用哈希算法实现
TreeSet:使用二叉树实现
无法从Set集合中取出特定的元素。Set是不可重复的。
Set<String> set = new HashSet<String>();
set.add("one");
set.add("two");
set.add("three");
//遍历只能使用迭代器
Iterator<String> it = set.iterator();
while (it.hasNext()) {
String string = it.next();
System.out.println(string);
}
1、HashSet和hashCode方法的关系
HashSet是Set接口的实现类,通过哈希表实现;在将对象加入到HashSet集合中时,需要获取对象的hashCode值通过hash算法索引到对应的存储空间。
具体是:a.当一个对象要插入到HashSet中时,首选获取对象的hashCode值,进行hash运算确定存储空间;
b.当通过contains方法判断集合中是否包含某个对象时,需要首先根据该对象的hashCode值索引到特定的空间,然后在和空间中的对象调用equels方法进行比较,这种查找方式不同于线性表的逐个比较,有很高的效率。
HashSet在add时,会根据该元素的hashCode值进行计算,来决定元素的位置。返回的是一个整数。
set也是集合,也可以使用Comparable。
2、hashCode方法
对于重写了equals方法的对象,一般要妥善的重写继承自Object类的hashCode方法(Object提供的hashCode方法将返回该对象所在内存地址的整数形式)。
重写hashCode方法需要主义两点:其一,与equals方法的一致性,即equals比较返回true的两个对象的hashCode方法返回值应该相同;其二,hashCode返回的数值应该符合哈希算法的要求。试想,如果有很多对象的hashCode方法返回值都相同,则会大大降低hash表的效率,一般情况下可以使用IDE提供的工具自动生成hashCode方法。
Object中提供的方法,默认是返回该对象的地址的整数形式。
注:对于重写了equals方法的类,应该也重写hashCode()。
重写hashCode的要求:
1)与equals保持一致,equals返回true的时候,两个对象的hashCode值也应该相同。
2)hashcode值应该是一个稳定的值,在对象内容不发生改变的情况下,hashCode()方法返回值不应该改变。所谓对象内容不发生变化,指的是参与equals比较逻辑的内容不发生变化。
每个集合的实现类都支持一个复制构造器。可以在创建该集合时将给定的集合中的元素存入当前集合。
注意:通过复制构造器我们仅仅是创建了一个新集合,对于元素来讲,并没有被复制!
public class Demo1_Set { public static void main(String[] args) { Set<Point> s = new HashSet<Point>(); s.add(new Point(1,2)); s.add(new Point(1,2)); s.add(new Point(1,3)); System.out.println(s);//[[x=1, y=3], [x=1, y=2]] //重写了hashCode方法,使其他们equals相等的hashCode也相等。 //如果不重写hashCode方法,尽管他们的equals为true, //但是他们的hashCode返回不同,HashSet将不会给这两个对象进行equals比较的机会。 } } class Point{ private int x; private int y; public Point(int x, int y) { this.x = x; this.y = y; } @Override public int hashCode() { //根据x y 数值计算出,如果两个对象的xy相等,则他们的hashCode也相等,显然符合equals方法原则。 final int prime = 31; int result = 1; result = prime * result + x; result = prime * result + y; return result; } @Override public boolean equals(Object obj) { if(obj instanceof Point){ return ((Point)obj).x == this.x && ((Point)obj).y == this.y; } return false; } @Override public String toString() { return "[x=" + x + ", y=" + y + "]"; } }
二、Map集合
Map定义的集合又称为查找表,用于存储所谓“Key-Value”映射对。作为key的对象在集合中不可以重复。
map不是Collection的子类,根据内部实现的不同,常见的是:
HashMap,使用Hash算法实现。
TreeMap,使用二叉树实现。
1、常用方法
存取元素的方法:
1)V put(K key, Value)将value以key作为一对存入map
key在整个map中不能重复,就是key类型的对象的equala返回不能是true
如果使用了重复的key这样就会替换了value。返回值就是使用相同key被替换的value,如是第一次存入数据,返回的是null。
2)V get(Object key)
根据给定的key获取对应的value,若该key在map中不存在则返回null.
3)boolean containsKey(Object key)
判断集合中是否包含指定key.
3)boolean containsValue(Object value)
判断集合中是否包含指定value.
例:
Map<String,Point1> hashmap = new HashMap<String,Point1>(); hashmap.put("p1", new Point1(1,2)); hashmap.put("p2", new Point1(4,3)); hashmap.put("p3", new Point1(1,2)); System.out.println(hashmap); //如果使用了重复的key这样就会替换了value。 //返回值就是使用相同key被替换的value,如是第一次存入数据,返回的是null。 System.out.println(hashmap.put("p3", new Point1(12,10))); //获取指定key的知 System.out.println(hashmap.get("p3")); //判断集合中是否包含指定key. System.out.println(hashmap.containsKey("p1")); //判断集合中是否包含指定value. System.out.println(hashmap.containsValue(new Point1(4,3)));
2、HashMap基本原理
HashMap存放元素时,会根据key的hashCode值进行哈希算法,用来计算这一组key-value应存放的位置,若key的hashCode值根据计算得到的位置已经有元素占用了,那么该值会放在那个元素的后边,因为HashMap中存放元素在位置相同的地方使用链表的形式存放每组数据的。
HashMap中存放数据的数组叫做散列数组。
容量:散列数组的大小。
初始容量:刚创建HashMap时,散列数组的大小默认16。
大小:hashmap中存储的元素数量。
加载因子:根据实验表明,加载因子保持在0.75一下,hashMap检索效率最高。
加载因子=大小/容量
鉴于hashmap的存储于原理,存入HashMap的key必须要妥善的重写hashCode方法。
HashMap遍历可以有三种方式:
1)只遍历key,使用keySet得到的是一个Set集合。
2)只遍历value,使用values得到的是一个Collection集合,如果以set返回会丢失元素。
3)遍历key-value对
例:
Map<String, Point2> map = new HashMap<String, Point2>(); map.put("p1", new Point2(2,2)); map.put("p2", new Point2(3,2)); map.put("p3", new Point2(5,6)); /** * keySet()方法,将map中所有的key以Set集合的形式返回。 */ Set<String> keySet = map.keySet(); for (String string : keySet) { System.out.print(string+" ");//p3 p2 p1 } System.out.println(keySet);//[p3, p2, p1] /** * values()方法,获取map中所有的value值 * 返回不是Set集合,是list集合。 */ Collection<Point2> c = map.values(); System.out.println(c);//[[x=5, y=6], [x=3, y=2], [x=2, y=2]] /** * 遍历key-value对 * entrySet():将map中的元素以key-value对存入set集合并返回 * key-value对,map用其一个内部类Entry的实例去保存。 * Entry支持泛型。它的泛型定义应该和map的泛型保持一致。 */ Set<Entry<String, Point2>> entries = map.entrySet(); for (Entry<String, Point2> entry : entries) { /** * 通过Entry的方法获取key和value */ System.out.println(entry.getKey()+":"+entry.getValue()); //p3:[x=5, y=6] //p2:[x=3, y=2] //p1:[x=2, y=2] } //或: Iterator<Entry<String, Point2>> it = entries.iterator(); while (it.hasNext()) { Entry<String, Point2> entry = it.next(); System.out.println(entry.getKey()+":"+entry.getValue()); }