Java基础进阶_day08_(Map集合,可变参数)
1. Map集合
Map集合:将键映射到值的对象.Map集合是双列集合的顶层接口.
# Map集合特点:
* A:一个映射不能包含重复的键(相当于是Collection集合的Set集合);
* B:每个键最多只能映射到一个值;
* C:值可以重复(相当于是Collection集合的List集合).
Map集合与Collection集合的区别:
# Map集合存储的元素是成对出现的,其中键是唯一的,值是可以重复的;
# Collection集合存储的元素是单独出现的,其子接口List集合存储的是元素是可重复的,子接口Set集合存储的元素是唯一的.
集合中的数据结构:
# Map集合的底层数据结构是针对键有效的,对值无效;
# Collection集合的底层数据结构是针对存储的元素有效.
Map集合功能概述:
添加功能:
V put(K key,V value):将指定的键映射到值,返回被替换的值;
获取功能:
Set<Map.Entry<K,V>> entrySet():获取集合键值对的集合;
V get(Object key):获取指定键对应的值,没有则返回null;
Set<K> keySet():返回该集合的键集合;
Collection<V> values():返回该集合的值的集合;
删除功能:
void clear():删除集合中所有的键值对;
V remove(Object key):删除指定键对应的值,并将删除的值返回(key不返回),没有返回null;
判断功能:
boolean containsKey(Object key):判断集合中是否包含指定键;
boolean containsValue(Object value):判断集合中是否包含指定的值;
boolean isEmpty():判断集合是否为空;
长度功能:
int size():返回集合中键值对的对数.
Map集合的遍历方式:
# 方式1:通过keySet()方法获取Map的键的Set集合,通过遍历key的集合(get()方法)获取key对应的value值.
# 方式2:先获取Map集合的键值对对象的集合,通过遍历获取的集合获取每一个键值对对象,获取键值对对象的键和值.
案例:
public class MyMapDemo {
public static void main(String[] args) {
//创建集合对象
Map<Integer, String> m = new HashMap<Integer, String>();
// V put(K key,V value)
System.out.println(m.put(1, "郭靖"));
m.put(2, "黄蓉");
System.out.println(m);
// V get(Object key)
System.out.println(m.get(1));
System.out.println(m.get(2));
// Set<K> keySet():
Set<Integer> keySet = m.keySet();
for (Integer integer : keySet) {
System.out.println(integer);
}
// Collection<V> values()
Collection<String> values = m.values();
for (String string : values) {
System.out.println(string);
}
// void clear()
// m.clear();
// System.out.println(m);
// V remove(Object key)
System.out.println(m.remove(1));
System.out.println(m.remove(3));
// boolean containsKey(Object key)
System.out.println(m);
System.out.println(m.containsKey(1));
// boolean containsValue(Object value)
System.out.println(m.containsValue("郭靖"));
// boolean isEmpty()
System.out.println(m.isEmpty());
// int size()
System.out.println(m.size());
// 遍历集合,方式1
Map<String, String> map = new HashMap<String, String>();
map.put("郭靖", "黄蓉");
map.put("杨康", "穆念慈");
map.put("周伯通", "瑛姑");
Set<String> set = map.keySet();
for (String string : set) {
System.out.println(string+"..."+map.get(string));
}
// 遍历集合,方式1
Set<Map.Entry<String, String>> entrySet = map.entrySet();
for (Map.Entry<String, String> entry : entrySet) {
System.out.println(entry.getKey()+"..."+entry.getValue());
}
}
}
1.1 HashMap集合
HashMap集合:是基于哈希表的Map集合接口的实现类,其有个子类LinkedHashMap[键值对有序(存取顺序)].
# (键)底层数据结构是哈希表.
# 特点:键值对集合,键唯一,键值对无序(存储顺序),值可以重复.
* 哈希表保证了键的唯一性.
* 任何非null对象都可以用作键或值.
注意事项:
# 由于HashMap集合键的底层数据结构是哈希表,如果键的内容是自定义类,则需要该类重写hashCode和equals方法,否则无法保证键的唯一性.
# HashMap与~~Hashtable~~集合:
* HashMap集合:线程不安全,效率高,键和值可以为null;
* Hashtable集合:线程安全,效率低,键和值不允许为null.
案例:
public class MyMap_HashMapDemo {
public static void main(String[] args) {
HashMap<Student, String> hm = new HashMap<Student, String>();
hm.put(new Student("郭靖", 23), "12");
hm.put(new Student("黄蓉", 23), "13");
hm.put(new Student("洪七公", 40), "14");
hm.put(new Student("郭靖", 23), "15");
Set<Student> keySet = hm.keySet();
for (Student student : keySet) {
String s = hm.get(student);
System.out.println(student.getName()+"..."+student.getAge()+"..."+s);
}
}
}
class Student {
private String name;
private int age;
public Student() {}
public Student(String name, int age) {
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;
}
// 重写hashCode和equals方法
@Override
public int hashCode() {
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;
}
}
1.2 LinkedHashMap集合
LinkedHashMap集合:Map接口的哈希表和链接列表实现,具有可预知的迭代顺序(存储和取出顺序一致),是LinkedHashMap集合是HashMap集合类的子类.
# 底层数据结构是哈希表和链表.
* 特点:键唯一,值可重复,有序(存取顺序一致).
* 哈希表保证了键的唯一性,链表保证了键值对的存取顺序一致.
案例:
public class MyMap_HasMap_LinkedHashMapDemo {
public static void main(String[] args) {
LinkedHashMap<String, String> hm = new LinkedHashMap<String, String>();
hm.put("123", "java");
hm.put("1234", "android");
hm.put("123", "javaEE");
hm.put("1235", "java");
Set<String> keySet = hm.keySet();
for (String string : keySet) {
System.out.println(string+"..."+hm.get(string));
}
}
}
1.3 TreeMap集合
TreeMap集合:是实现了Map集合接口的子类.
# 底层数据结构是红黑树(自平衡的二叉树).
# 特点:键唯一,值可重复,无序(元素存取顺序).
* 键的红黑树数据结构保证了键的唯一性和排序.
构造方法:
public TreeMap():该构造方法的键是自然排序;
public TreeMap(Comparator<? super K> comparator):该构造方法创建的对象的键是按照比较器comparator进行排序.
注意事项:
# 键自然排序:无参构造
* 当键是自定义对象时,需要该对象所属的类实现Comparable接口,并实现其中的compareTo方法,在该方法中定义排序规则.
# 键比较器排序:有参数构造
* 当键是自定义对象时,在创建集合对象时,使用实现Comparator接口的匿名内部类,并实现其中的compare方法,在方法中定义排序规则.
案例:
public class MyMap_TreeMapDemo {
public static void main(String[] args) {
// 创建集合对象
TreeMap<Student, String> tm = new TreeMap<Student, String>(new Comparator<Student>() {
// 重写方法,定义排序规则
@Override
public int compare(Student s1, Student s2) {
// 主要条件,年龄
int num = s2.getAge() - s1.getAge();
// 次要条件,姓名
int num2 = num==0?s1.getName().compareTo(s2.getName()):num;
return num2;
}
});
tm.put(new Student("郭靖", 23), "12");
tm.put(new Student("黄蓉", 23), "13");
tm.put(new Student("洪七公", 40), "14");
tm.put(new Student("郭靖", 23), "15");
Set<Student> keySet = tm.keySet();
for (Student student : keySet) {
String s = tm.get(student);
System.out.println(student.getName()+"..."+student.getAge()+"..."+s);
}
// 练习
// 统计一个字符串中各个字符出现的次数
test01();
}
/* * 统计一个字符串中各个字符出现的次数 */
public static void test01() {
// 定义存储字符的集合
TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>();
// 定义键盘录入对象
Scanner sc = new Scanner(System.in);
// 定义接收键盘录入的字符串
System.out.println("请输入一个字符串:");
String s = sc.nextLine();
// 将字符串转换为字符数组
char[] chs = s.toCharArray();
// 遍历字符数组,统计各个字符出现的次数
for (int i = 0; i < chs.length; i++) {
if(tm.containsKey(chs[i])) {
int num = tm.get(chs[i]);
num++;
tm.put(chs[i], num);
}else {
tm.put(chs[i], 1);
}
}
// 定义字符串缓冲区对象
StringBuilder sb = new StringBuilder();
Set<Character> ketSet = tm.keySet();
for (Character character : ketSet) {
sb.append("\""+character+"\"").append("(").append(tm.get(character)).append(")");
}
// 输出结果
System.out.println(sb.toString());
}
}
// 自定义类
class Person {
private String name;
private int age;
public Person() {}
public Person(String name, int age) {
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;
}
}
2. 可变参数
可变参数:定义方法时不确定参数的个数.
使用格式:
修饰符 返回值类型 方法名 (数据类型... 变量名) {}
注意事项:
# 方法的变量名其实是一个数组;
# 如果一个方法有可变参数并且有多个参数,则可变参数必须是最后一个参数.
Arrays工具类:
public static <T> List<T> asList(T... a):将数组转换为集合.
注意事项:该方法转换成的集合本质还是数组,长度不变,所以不支持改变数组长度的操作(增删),修改可以.
案例:
public class MyArgsDemo {
public static void main(String[] args) {
// 调用可变参数方法
System.out.println(sum(1,2,3));
System.out.println(sum(1,2));
System.out.println(sum(1,2,3,4));
// 多个参数的可变参数,可变参数必须最后一个参数
System.out.println(sum1(2.4,1,2,3));
// 将数组转换为集合
String[] s = {"java","python","android"};
List<String> asList = Arrays.asList(s);
// 可变参数
// List<String> asList = Arrays.asList("java","python","android");
// List<String> asList = Arrays.asList("java","python");
for (String string : asList) {
System.out.println(string);
}
// asList.add("java"); // java.lang.UnsupportedOperationException
// asList.remove(0); // UnsupportedOperationException
asList.set(0, "java");
}
// 定义可变参数
public static int sum(int... num) {
int sum = 0;
// 使用增强for循环遍历数组
for (int i : num) {
sum += i;
}
return sum;
}
// 定义可变参数
public static int sum1(double num1, int... num2) {
int sum = 0;
// 使用增强for循环遍历数组
for (int i : num2) {
sum += i;
}
System.out.println(num1);
return sum;
}
}