java_day14_HashSet、TreeSet、增强for循环、Map、HashMap、TreeMap、可变参数
一、HashSet
Set:
HashSet: 底层数据结构是哈希表,查找速度快,且元素唯一
HashSet中的add方法实际上调用的是HashMap中的put方法
底层和元素的hashCode方法值有关
我们发现,底层判断待插入的元素是否已经存在哈希表中的方式是:
将待插入的元素的哈希值与已经存储在哈希表中元素哈希值进行比较,
然后再调用待插入的元素的equals方法比较已经存储在哈希表中元素。
若哈希值一样,且equals结果为true,就表示这两个元素是同一个元素,不做添加
结论:
若想要使用HashSet对元素进行去重,需要元素类型本身重写hashCode方法和equals方法。
public class HashSetDemo1 {
public static void main(String[] args) {
//使用HashSet存储字符串元素
HashSet<String> set1 = new HashSet<>();
//添加元素
set1.add("hello");
set1.add("world");
set1.add("hello");
set1.add("java");
set1.add("hello");
set1.add("hadoop");
System.out.println("set1: " + set1);
}
}
LinkedHashSet
Collection:
List:
ArrayList
Vector
LinkedList
Set:
HashSet:底层数据结构是哈希表,元素唯一,无序
- LinkedHashSet:底层数据结构是哈希表和双链表。哈希表保证元素唯一,双链表保证元素有序,元素唯一
二、TreeSet
Collection:
List:
Set:
HashSet:
- LinkedHashSet:
TreeSet: 底层数据结构是红黑树(自平衡二叉树),具备了可预测的排序
- 自然排序
- 比较器排序
TreeSet中的add方法实际上是调用了TreeMap中的put方法
Collection:
List:
Set:
HashSet:
- LinkedHashSet:
TreeSet: 底层数据结构是红黑树(自平衡二叉树),具备了可预测的排序
- 自然排序
- 比较器排序
TreeSet中的add方法实际上是调用了TreeMap中的put方法
要想使用TreeSet集合存储自定义对象且使用的是无参构造方法创建TreeSet集合对象的话, 需要元素类型实现Comparable<元素类型>接口,实现compareTo方法 compareTo方法根据需求来定制
自定义一个Techer类,该类实现了Comparable接口,并重写其中的CompareTO方法
Techer类部分代码
@Override
public int compareTo(Teacher o) {
//cmp = k.compareTo(t.key);
// this - 待插入元素
// o - 要比较的根元素
//当姓名和年龄一样的时候去重,年龄需要从小到大排序
// return this.age - o.getAge();
//显式条件
int i1 = this.age - o.getAge();
//隐式条件
//当年龄一样的时候,姓名不一定一样
return (i1==0)?this.name.compareTo(o.name):i1;
测试类
public class TreeSetDemo2 {
public static void main(String[] args) {
//使用TreeSet存储自定义对象
TreeSet<Teacher> set1 = new TreeSet<>();
//需求:当姓名和年龄一样的时候去重,年龄需要从小到大排序
Teacher t1 = new Teacher("笑哥", 18);
Teacher t2 = new Teacher("小虎", 15);
Teacher t3 = new Teacher("凯哥", 17);
Teacher t4 = new Teacher("笑哥", 18);
Teacher t5 = new Teacher("杨老板", 18);
set1.add(t1);
set1.add(t2);
set1.add(t3);
set1.add(t4);
set1.add(t5);
for (Teacher teacher : set1) {
System.out.println(teacher);
}
}
}
还有另外一种方法,使用比较器排序,在创建TreeSet集合时传入一个比较器
代码案例
public class TreeSetDemo3 {
public static void main(String[] args) {
//使用比较器排序,按照年龄从小到大排序
// public TreeSet(Comparator<? super E> comparator) {
// this(new TreeMap<>(comparator));
// }
TreeSet<Cat> set1 = new TreeSet<>(new Comparator<Cat>() {
@Override
public int compare(Cat o1, Cat o2) {
// o1是待插入的元素
// o2是要比较的根元素
int i1 = o1.getAge() - o2.getAge();
return (i1 == 0) ? o1.getName().compareTo(o2.getName()) : i1;
}
});
Cat c1 = new Cat("汤姆", 8);
Cat c2 = new Cat("黑猫警长", 2);
Cat c3 = new Cat("加菲猫", 4);
Cat c4 = new Cat("汤姆", 8);
Cat c5 = new Cat("哆啦A梦", 6);
set1.add(c1);
set1.add(c2);
set1.add(c3);
set1.add(c4);
set1.add(c5);
for (Cat cat : set1) {
System.out.println(cat);
}
}
}
三、增强for循环
增强for循环:是用来替代迭代器的,只能遍历数组以及Collection集合
语句定义格式:
for(元素的类型 变量名 : 数组|Collection集合){
直接使用变量名相当于使用元素;
}
代码案例
public class ForDemo1 {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
list1.add("hello");
list1.add("world");
list1.add("java");
list1.add("hello");
list1.add("hadoop");
for (String s : list1) {
System.out.println(s + "--" + s.length());
}
System.out.println("-----------------------");
int[] arr = {11,22,33,44,55};
for(int i:arr){
System.out.println(i);
}
}
}
例题:
键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台
public class TreeSetTest1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
//创建一个TreeSet集合
TreeSet<Student2> set1 = new TreeSet<>(new Comparator<Student2>() {
@Override
public int compare(Student2 o1, Student2 o2) {
//显式条件:按照总分从高到低输出到控制台
int i1 = o2.getSumScore() - o1.getSumScore();
//隐式条件
//总分一样,语文成绩不一定一样
int i2 = (i1 == 0) ? o2.getChinese() - o1.getChinese() : i1;
//总分一样,语文成绩一样,数学成绩不一定一样
int i3 = (i2 == 0) ? o2.getMath() - o1.getMath() : i2;
//各科成绩一样,姓名不一定一样
return (i3 == 0) ? o2.getName().compareTo(o1.getName()) : i3;
}
});
for(int i=1;i<=5;i++){
System.out.println("请输入第 "+i+" 个学生的信息");
System.out.print("请输入姓名: ");
String name = sc.next();
System.out.print("请输入该学生的语文成绩: ");
int chinese = sc.nextInt();
System.out.print("请输入该学生的数学成绩: ");
int math = sc.nextInt();
System.out.print("请输入该学生的英语成绩: ");
int english = sc.nextInt();
set1.add(new Student2(name,chinese,math,english));
}
System.out.println("学生信息录入完毕!!");
System.out.println("================= 学生成绩汇总 ===================");
System.out.println("姓名\t\t语文成绩\t\t数学成绩\t\t英语成绩\t\t总分");
//遍历集合
for (Student2 student2 : set1) {
System.out.println(student2.getName()+"\t\t"+
student2.getChinese()+"\t\t"+
student2.getMath()+"\t\t"+
student2.getEnglish()+"\t\t"+
student2.getSumScore());
}
}
}
四、Map
Map集合:元素是键值对构成的
Map特点:
1、在同一个Map集合中,键是唯一的
2、在同一个Map集合中,值可以发生重复
3、一对键值,表示Map集合中的一个元素
Map集合中的方法:
V put(K key,V value)
V remove(Object key)
void clear()
boolean containsKey(Object key)
boolean containsValue(Object value)
boolean isEmpty()
int size()
V get(Object key)
Set<K> keySet()
Collection<V> values()
Set<Map.Entry<K,V>> entrySet()
代码案例
public class MapDemo1 {
public static void main(String[] args) {
HashMap<Integer, String> map1 = new HashMap<>();
//V put(K key,V value) 向集合中添加一对元素 返回键原本的旧值
// System.out.println(map1.put(1001, "李刚"));
// System.out.println("map1: " + map1);
// System.out.println("----------------------");
// System.out.println(map1.put(1001, "xiaohu"));
// System.out.println("map1: " + map1);
map1.put(1001, "李刚1");
map1.put(1002, "李刚2");
map1.put(1003, "李刚3");
map1.put(1001, "李刚4");
map1.put(1004, "李刚5");
System.out.println("map1: " + map1);
System.out.println("----------------------");
//V remove(Object key) 根据键移除一个键值对
// System.out.println(map1.remove(1001));
// System.out.println("map1: " + map1);
//void clear()
// map1.clear();
// System.out.println("map1: " + map1);
//boolean containsKey(Object key) 判断键是否存在
// System.out.println(map1.containsKey(1001));
//boolean containsValue(Object value) 判断值是否存在
// System.out.println(map1.containsValue("李刚1"));
//boolean isEmpty() 判断Map集合中是否有键值对
// System.out.println(map1.isEmpty());
//int size() 返回Map集合中键值对的元素个数
// System.out.println(map1.size());
//V get(Object key) 根据键获取值
// System.out.println(map1.get(1001));
// System.out.println(map1.get(1009)); // null
//Set<K> keySet() 获取所有的键
// Set<Integer> keySet = map1.keySet();
// for (Integer i : keySet) {
// System.out.println(i);
// }
//Collection<V> values() 获取所有的值
// Collection<String> values = map1.values();
// for (String value : values) {
// System.out.println(value);
// }
}
}
遍历Map集合
public class MapDemo2 {
public static void main(String[] args) {
//Map集合遍历
HashMap<Integer, String> map1 = new HashMap<>();
map1.put(1001, "李刚1");
map1.put(1002, "李刚2");
map1.put(1003, "李刚3");
map1.put(1001, "李刚4");
map1.put(1004, "李刚5");
System.out.println("map1: " + map1);
System.out.println("----------------------");
// 方式1:获取所有的键,遍历键,根据键获取值
// Set<Integer> keySet = map1.keySet();
// for (Integer key : keySet) {
// String value = map1.get(key);
// System.out.println(key + "-" + value);
// }
// 方式2:直接获取所有的键值对,遍历每一个键值对得到每一个键和值
//Set<Map.Entry<K,V>> entrySet()
Set<Map.Entry<Integer, String>> entries = map1.entrySet();
for (Map.Entry<Integer, String> entry : entries) {
Integer key = entry.getKey();
String value = entry.getValue();
System.out.println(key + ":" + value);
}
}
}
1、HashMap
HashMap<Student3,String>
Map的唯一性指的是键的唯一性,HashMap中需要键的类型要重写hashCode()方法和equals方法
二、TreeMap
案例:
"aababcabcdabcde",获取字符串中每一个字母出现的次数要求结果:
控制台输出"a(5)b(4)c(3)d(2)e(1)"
public class TreeMapTest1 {
public static void main(String[] args) {
String s1 = "aababcabcdabcde";
TreeMap<Character, Integer> map1 = new TreeMap<>();
//将字符串转字符数组
char[] chars = s1.toCharArray();
//遍历字符数组向集合中添加
for (char c : chars) {
if (map1.containsKey(c)) {
map1.put(c, map1.get(c) + 1);
} else {
map1.put(c, 1);
}
}
StringBuilder sb = new StringBuilder();
Set<Map.Entry<Character, Integer>> entries = map1.entrySet();
for (Map.Entry<Character, Integer> entry : entries) {
Character c = entry.getKey();
Integer count = entry.getValue();
sb.append(c).append("(").append(count).append(")");
}
String resStr = sb.toString();
System.out.println("结果为:" + resStr);
}
}
五、可变参数
代码案例
public class KeBianCanShuDemo {
public static void main(String[] args) {
//需求1:求两个int类型的数之和
int a = 3;
int b = 4;
sum(a, b);
//需求2:求三个int类型的数之和
int c = 5;
sum(a, b, c);
//需求3:求四个int类型的数之和
int d = 6;
sum(a, b, c, d);
int e = 7;
sum(a,b,c,d,e);
//需求:传入一个人的姓名和若干门考试成绩,求这个人的总分
getSumScoreWithName("李刚",98,99,100);
getSumScoreWithName("钱志强",78,88);
// getSumScoreWithName2(78,88,"钱志强");
//可变参数的应用
//Arrays工具类中有一个方法是将传入的参数封装成一个List集合
List<Integer> list = Arrays.asList(11, 22, 33, 44, 55); // ArrayList
}
//可变参数只能在最后一个参数定义出来
// public static void getSumScoreWithName2(int... arr,String name) {
// int sum = 0;
// for (int i : arr) {
// sum+=i;
// }
// System.out.println(name+"总分为:"+sum);
// }
public static void getSumScoreWithName(String name,int... arr) {
int sum = 0;
for (int i : arr) {
sum+=i;
}
System.out.println(name+"总分为:"+sum);
}
public static void sum(int... arr) {
int sum = 0;
for (int i : arr) {
sum+=i;
}
System.out.println(sum);
}
// public static void sum(int a, int b) {
// System.out.println(a + b);
// }
//
// public static void sum(int a, int b, int c) {
// System.out.println(a + b + c);
// }
//
// public static void sum(int a, int b, int c, int d) {
// System.out.println(a + b + c + d);
// }
}