一、Set集合的特点
Set集合的特点:
无序(存储和读取的顺序有可能不一样);
不允许重复(要求元素唯一);
没有索引。
利用HashSet存储字符串并遍历(三种遍历方法):
public static void main(String[] args) {
//创建集合对象
Set<String> set = new HashSet<String>();
//添加元素
set.add("hello");
set.add("world");
set.add("bupt");
//遍历集合对象(分为三种:数组遍历、迭代器遍历、增强for循环)
//数组遍历
Object[] objs = set.toArray();
for(int i=0; i < objs.length; i++) {
System.out.println(objs[i]);
}
//迭代器遍历
Iterator<String> it = set.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
//增强for循环遍历
for(String s : set){
System.out.println(s);
}
}
二、HashSet存储自定义对象并遍历
通过查看源码发现:
HashSet的add方法会使用当前集合中的每一个元素的Hash值与新添加元素的Hash值进行比较:如果Hash值(通过hashCode方法获取)不一样,则直接添加新的元素;如果Hash值一样,则比较比较地址值或者使用元素中重写的equals方法进行比较,若比较结果一样,则认为元素重复,不再添加,若比较结果不一样,则可以添加。
public class test {
public static void main(String[] args) {
//创建集合对象
HashSet<Student> set = new HashSet<Student>();
//创建自定义类对象
Student s0 = new Student("hxf2",20);
Student s1 = new Student("hxf",18);
Student s2 = new Student("hxf1",19);
Student s3 = new Student("hxf2",20);
//将自定义类对象添加到集合中
set.add(s1);
set.add(s2);
set.add(s3);
for(Student s : set){ //增强for循环遍历集合
System.out.println(s);
System.out.println(s.hashCode());
}
}
}
class Student{
private String name;
private int age;
public Student(String name, int age) { //构造方法,为了初始化
this.name = name;
this.age = age;
}
@Override
public String toString() { //使用Eclipse自动生成,用于显示自定义类Student的成员变量
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public boolean equals(Object obj) {
if(this == obj) { //提高程序效率
return true;
}
if(obj == null) { //更加严谨
return false;
}
if(this.getClass() != obj.getClass()) { //提高代码健壮性,如果传进来的类跟Student类不相关,则不能向下转型
return false;
}
Student stu = (Student)obj; //向下转型
if(this.age != stu.age) {
return false;
}
if(!this.name.equals(stu.name)) {
return false;
}
return true;
}
@Override
public int hashCode() { //使用随着类成员变量变化的的hashCode方法
return age + name.hashCode();
}
}
注:因为Object类中有equals和hashCode方法,所以在Student自定义类默认继承Object类(但是Object类中的equals方法和hashCode不能满足自定义类的成员比较),可以重写Object类中的方法。
举个例子:String类重写了Object类的equals和hashCode方法,以满足针对不同的字符串,得到不同的hash值,相同的字符串得到相同的hash值,从而来进行“去重”,即去除重复。
三、Collections工具类
Collections与Collection的区别:
Collection是集合体系的最顶层,包含了集合体系共性;
Collections是一个工具类,其中的方法大多为静态方法,用于操作Collection集合。
方法举例:
static int binarySearch(List<? extends Comparable<? super T>> list, T key) : 使用二分搜索法搜索指定列表,以获得指定对象。
static void copy(List<? super T> dest, List<? extends T> src) :将所有元素从一个列表复制到另一个列表。
static void fill(List<? super T> list, T obj) : 使用指定元素替换指定列表中的所有元素。
static void reverse(List<?> list) :反转指定列表中元素的顺序。
static <T extends Comparable<? super T>> void sort(List list) :根据元素的自然顺序 对指定列表按升序进行排序。
static void swap(List<?> list, int i, int j) :在指定列表的指定位置处交换元素。
代码举例:
public class test {
public static void main(String[] args) {
//创建集合对象
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(3);
list.add(4);
list.add(2);
list.add(5);
int index = Collections.binarySearch(list, 3);
System.out.println(index);
}
}
举例:模拟斗地主发牌
public static void main(String[] args) {
//创建扑克牌
String arr1[] = {"黑桃","红桃","方片","梅花"};
String arr2[] = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
ArrayList<String> box = new ArrayList<String>();
for(int i=0; i < arr1.length; i++) {
for(int j=0; j < arr2.length; j++) {
box.add(arr1[i] + arr2[j]);
}
}
box.add("大王");
box.add("小王");
//洗牌,调用Collections工具类,将集合内的字符串对象打乱
Collections.shuffle(box);
//给三个同学发牌
ArrayList<String> person1 = new ArrayList<String>();
ArrayList<String> person2 = new ArrayList<String>();
ArrayList<String> person3 = new ArrayList<String>();
for(int i=0; i < box.size()-3; i++) {
if(i%3 == 0) {
person1.add(box.get(i));
}
else if(i%3 == 1) {
person2.add(box.get(i));
}
else if(i%3 == 2) {
person3.add(box.get(i));
}
}
for(int i=box.size()-3; i < box.size(); i++) {
System.out.println("底牌"+box.get(i));
}
System.out.println(person1);
System.out.println(person2);
System.out.println(person3);
}
}
四、Map接口
Map接口概述:将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
Map和Collection的区别:
Map:是一个双列集合,常用于处理有对应关系的数据,键key是不可以重复的,我们也称之为“夫妻对集合”
Collection:是单列集合,Collection接口有不同的子体系,有的允许重复并且有索引有序(比如:ArrayList和LinkedList),有的不允许重复并且无序(比如:HashSet),我们也称之为“单身汉集合”;
Map的常用功能:
映射功能:
V put(K key, V value) :就是将key映射到value,如果key存在,则覆盖value,并将原来的value值返回;如果key不存在,则添加key以及相应的value;
获取功能:
V get(Object key) :根据键key的值,返回对应value;
int size() :返回对应关系的个数;
判断功能:
boolean containsKey(Object key) :判断指定key是否存在;
boolean containsValue(Object value) :判断指定的value是否存在;
boolean isEmpty() :判断是否有对应关系;
删除功能:
void clear() :清空所有的对应关系;
V remove(Object key) :根据指定的key删除对应关系,并返回key所对应的值;
遍历功能:
Set<Map.Entry<K,V>> entrySet() : 返回此映射中包含的映射关系的 Set 视图。
Map获取所有的key和value方法:
//Set<K> keySet() 以Set的形式返回所有的key
Set<String> keys = map.keySet();
for(String key:keys){ //遍历Set集合
System.out.println(key);
}
//Collection<V> values(): 以Collection的形式返回所有的value
Collection<String> values = map.values();
for(String value:values){ //遍历Collection集合
System.out.println(value);
}
Map的第一种遍历方式:
获取所有元素的key值,再根据key值找到value值;
public static void main(String[] args) {
//创建一个Map对象
Map<String,String> map = new HashMap<String,String>();
//添加映射关系
map.put("邓超","孙俪");
map.put("李晨","范冰冰");
map.put("黄晓明", "杨颖");
//遍历Map对象
Set<String> keys = map.keySet();
for(String key:keys) {
String value = map.get(key);
System.out.println("丈夫:"+key+" "+"妻子:"+value);
}
}
Map的第二种遍历方式:
通过内部类对象来获取key和value的值(举例:这里的内部类可认为是结婚证类,来获取丈夫和妻子的值);
我们写的内部类如下:
class Entry<K,V> {
K key;
V value;
public Entry(K key, V value){
this.key = key;
this.value = value;
}
public K getKey(){
return key;
}
public V getValue(){
return value;
}
}
实际在Map接口中,Entry<K,V>是一个子接口,其在Map的实现子类AbstractMap类中被重写,重写形式与上述代码类似,利用Entry<K,V>内部类实现Map的遍历方式代码为:
利用 Map接口中的Set<Map.Entry<K,V>> entrySet() 函数。
public static void main(String[] args) {
//创建一个Map对象
Map<String,String> map = new HashMap<String,String>();
//添加映射关系
map.put("邓超","孙俪");
map.put("李晨","范冰冰");
map.put("黄晓明", "杨颖");
//遍历Map对象
Set<Map.Entry<String, String>> entrys = map.entrySet();
for(Map.Entry<String, String> entry:entrys) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println("丈夫:"+key+" "+"妻子:"+value);
}
}
五、综合实例
key值为自定义对象实例(包含两种遍历方法和去重):
自定义对象为:
public class Student {
public String name;
public int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() { //用于显示
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public int hashCode() { //与equals方法一起,去重复
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 static void main(String[] args) {
//创建一个Map对象
Map<Student,String> map = new HashMap<Student,String>();
//创建学生对象
Student s1 = new Student("张三丰",18);
Student s2 = new Student("郭靖",30);
Student s3 = new Student("郭靖",30);
//添加映射关系
map.put(s1,"abc01");
map.put(s2,"abc02");
map.put(s3,"abc03");
//第一种遍历方式
Set<Student> keys = map.keySet();
for(Student key:keys) {
String value = map.get(key);
System.out.println(key+"学号:"+value);
}
System.out.println("----------------");
//第二种遍历方式
Set<Map.Entry<Student, String>> entrys = map.entrySet();
for(Map.Entry<Student, String> entry:entrys) {
Student key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"学号:"+value);
}
}
注:若这里直接使用Map<String,String>,则直接有去重功能,因为hashCode()函数、equals()函数都被重写过了,而Student类继承的是Object类。