集合:Map
Map接口概述在JDK1.2之前使用的是Dictionary抽象类(字典 = 映射)。JDK1.2之后,才有了Map(映射)接口。有时Map也被称之为字典,索引。将键映射到值的对象。(我们可以根据键快速查找到关联的值)Map中键是唯一的(不包含重复的键)每个键最多只能映射一个值Map的APIMap<String, String> map = new HashMap<>();
·
Map接口
概述
在JDK1.2之前使用的是Dictionary抽象类(字典 = 映射)。JDK1.2之后,才有了Map(映射)接口。
有时Map也被称之为字典,索引。
- 将键映射到值的对象。(我们可以根据键快速查找到关联的值)
- Map中键是唯一的(不包含重复的键)
- 每个键最多只能映射一个值
Map的API
Map<String, String> map = new HashMap<>();
map.put("刘强东", "章泽天");
map.put("文章", "马伊利");
map.put("王宝强", "马蓉");
map.put("贾乃亮", "李小璐");
增(改):
V put(K key, V value)
System.out.println(map.put("罗志祥","周扬青")) //null
System.out.println(map.put("王宝强",null)) // 马蓉
System.out.println(map);
void putAll(Map<? extends K, ? extends V> m)
Map<String, String> m = new HashMap<>();
map.put("罗志祥","周扬青");
map.put("王宝强",null);
map.putAll(m);
System.out.println(map); // 王宝强 = null
删:
void clear()
V remove(Object key)
System.out.println(map.remove("刘强东")); //章泽天
System.out.println(map.remove("罗志祥")); // 不存在返回null。但是返回null不一定不存在,可能value值就等于null。所以API提供了containsKey()这个方法。
System.out.println(map);
查:
V get(Object key)
System.out.println(map.get("文章")); // 马伊利
System.out.println(map.get("罗志祥")); //不存在返回 null。同remove,返回null不能就说其不存在
boolean containsKey(Object key)
map.put("王宝强", null);
System.out.println(map.get("王宝强") != null); // false
System.out.println(map.get("罗志祥") != null); // false
System.out.println(map.containsKey("王宝强")); // true
System.out.println(map.containsKey("罗志祥")); // false
boolean containsValue(Object value)
System.out.println(map.containsValue("李小璐")); //true
System.out.println(map.containsValue("周扬青")); //false
获取集合属性:
boolean isEmpty()
int size()
遍历:
Set<Map.Entry<K,V>> entrySet() // entry 键值对的英文 最适用于遍历键值对
//Map.Entry<K,V>
// K getKey()
// V getValue() :
// V setValue(V value)
Set<Map.Entry<String, String>> entries = map.entrySet();
for(Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
Set<K> keySet() // 最适用于遍历键
Set<String> keys = map.keySet();
for(String key : keys) {
String value = map.get(key);
System.out.println(key + "=" + value);
}
Collection<V> values() // 最适用于遍历值
//为什么values返回一个collection而不是set? 因为value可以重复
Collection<String> values = map.values();
for(String value : values) {
System.out.println(value); //不能根据 值 --> 键
}
Map的子类
HashMap(JDK中是数组+链表的方式实现的,但也可以用其他方法实现)
特性:
- 底层是哈希表
- 并允许null键和null值
- 不保证映射顺序,不保证顺序是恒久不变的
- 不同步的
实现了Map接口所有可选的操作
与JDK1.0的Hashtable很像。
HashMap<String, String> map = new HashMap<>();
map.put("刘强东", "章泽天");
map.put("文章", "马伊利");
map.put("王宝强", "马蓉");
map.put("贾乃亮", "李小璐");
map.put(null, "Allen");
map.put("Andrew", null);
System.out.println(map); //输出是无序的。允许null值和null键
构造方法(与HashSet相同)
HashMap():初始容量默认为16, 加载因子默认为0.75f
HashMap(int initialCapacity): 指定初始容量, 加载因子默认为0.75f
HashMap(int initialCapacity, float loadFactor): 指定初始容量,指定加载因子
HashMap(Map<? extends K,? extends V> m)
HashMap与Hashtable区别
共同点:底层数据结构都是哈希表
不同点:HashMap的键和值可以为null;Hashtable不可以;HashMap是不同步的,Hashtable是同步的
Hashtable<String, String> table = new Hashtable<>();
map.put("刘强东", "章泽天");
map.put("文章", "马伊利");
map.put("王宝强", "马蓉");
map.put("贾乃亮", "李小璐");
System.out.println(table); // 底层是哈希表,输出无序
//添加null键
table.put(null, "Allen"); //不允许,抛出NullPointerException
//添加null值
table.put("Andrew", null); //不允许,抛出NullPointerException
HashMap的子类LinkedHashMap
概述:
- HashMap的子类
- 底层数据结构是哈希表和双向链表,具有可预知的迭代顺序
- 哈希表保证了键的唯一性
- 双向链表定义了迭代顺序 = 插入顺序
- 不同步
LinkedHashMap<String, String> map = new LinkedHashMap<>(); //与性能良好的LRU算法的结构类似,但是不能直接用在LRU算法中,原因见最下面两个方法。没有改变它的迭代顺序。
map.put("刘强东", "章泽天");
map.put("文章", "马伊利");
map.put("王宝强", "马蓉");
map.put("贾乃亮", "李小璐");
map.put(null, "Allen");
map.put("Andrew", null);
System.out.println(map);
map.get("贾乃亮");
System.out.println(map); // 输出不变
map.put("王宝强", null);
System.out.println(map); // 输出不变
TreeMap
概述
- 底层数据结构是红黑树
- 如果创建对象时,没有传入 Comparator 对象,键将按自然顺序进行排序。
- 如果创建对象时,传入了 Comparator 对象,键将按 Comparator 进行排序。
- 不同步
构造方法(TreeSet一样)
TreeMap():键将按自然顺序进行排序, 要求键必须实现Comparable接口
TreeMap(Comparator<? super K> comparator):键将按Comparator进行排序
练习
存储自定义Student对象
Student s1 = new Student("Allen", 20);
Student s2 = new Student("Beyonce", 20);
Student s3 = new Student("Catalina", 20);
Student s4 = new Student("Diana", 20);
TreeMap<String, Student> map = new TreeMap<>();
map.put("Allen", s1);
map.put("Beyonce", s2);
map.put("Catalina", s3);
map.put("Diana", s4);
System.out.println(map); // 成功输出,因为使用无参构造方法时,只需要键实现了Comparable接口。此处的键是String,已经实现了Comparable接口。
System.out.println(map.size()); // 4
// 键为自定义类型,则必须实现Comparable接口或者构造方法传入comparator
TreeMap<Student, String> map = new TreeMap<>();
map.put(s1, "Allen");
map.put(s2, "Beyonce");
map.put(s3, "Catalina");
map.put(s4, "Diana");
System.out.println(map);
System.out.println(map.size());
// 构造方法传入Comparator匿名内部类
TreeMap<Student, String> map = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int cmp = s1.getName().compareTo(s2.getName());
cmp = cmp != 0 ? cmp : s1.getAge() - s2.getAge();
return cmp;
}
});
public class Student implements Comparable<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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student s1) {
int cmp = name.compareTo(s1.getName());
cmp = cmp != 0 ? cmp : age - s1.getAge();
return cmp;
}
底层是红黑树,特有API(TreeSet的底层数据结构TreeMap所以相似)
TreeMap<Character, String> map = new TreeMap<>();
map.put('A', "Allen");
map.put('B', "Beyonce");
map.put('C', "Catalina");
map.put('D', "Diana");
map.put('F', "Frances");
map.put('M', "Maria");
map.put('N', "Nika");
map.put('T', "Taylor");
K ceilingKey(K key)
System.out.println(map.ceilingKey('D')); // D
System.out.println(map.ceilingKey('E')); // F
System.out.println(map.ceilingKey('X')); // null
K floorKey(K key)
System.out.println(map.floorKey('D')); // D
System.out.println(map.floorKey('E')); // D
System.out.println(map.floorKey('0')); // null
K higherKey(K key)
System.out.println(map.higherKey('D')); // F
System.out.println(map.higherKey('E')); // F
System.out.println(map.higherKey('X')); // null
K lowerKey(K key)
System.out.println(map.lowerKey('D')); // C
System.out.println(map.lowerKey('E')); // D
System.out.println(map.lowerKey('0')); // null
K firstKey()
K lastKey()
System.out.println(map.firstKey()); //A
System.out.println(map.lastKey()); //T
System.out.println(map); //{A=Allen, B=Beyonce, C=...}
Map.Entry<K,V> pollFirstEntry()
Map.Entry<K,V> pollLastEntry()
System.out.println(map.pollFirstKey()); //A=Allen
System.out.println(map.pollLastKey()); //T=Taylor
NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)
//{A=Allen, B=Beyonce, C=Catalina, D=Diana, F=Frances, M=Maria, N=Nika, T=Taylor}
NavigableMap<Character, String> subMap = map.subMap('D', false, 'N', true);
System.out.println(subMap); // {F=Frances, M=Maria, N=Nika}
subMap.pollFirstEntry();
System.out.println(subMap); // {M=Maria, N=Nika}
System.out.println(map); // {A=Allen, B=Beyonce, C=Catalina, D=Diana, M=Maria, N=Nika, T=Taylor}
练习
// "aababcabcdabcde",获取字符串中每一个字符出现的次数要求结果:a(5)b(4)c(3)d(2)e(1)
思路1:如果只是小写英文字母
1. 创建大小为26的int数组,索引为0的位置记录'a'出现的次数..
2. 遍历字符串,获取每一个字符,讲对应索引位置的值+1
3. 遍历数组,拼接字符串
思路2:如果为任意字符
1. 创建TreeMap<Character, Integer> map对象
2. 遍历字符串,获取每一个字符,如果存在对应的字符则+1,不存在则设置为1
3. 遍历TreeMap,拼接字符串
public class Ex1 {
public static void main(String[] args) {
String s = "aababcabcdabcde";
TreeMap<Character, Integer> map = new TreeMap<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (map.containsKey(c)) map.put(c, map.get(c) + 1);
else map.put(c, 1);
}
StringBuilder sb = new StringBuilder();
Set<Map.Entry<Character, Integer>> entries = map.entrySet();
for (Map.Entry<Character, Integer> e : entries) {
sb.append(e.getKey()).append("(").append(e.getValue()).append(")");
}
System.out.println(sb);
}
}
/*给定一个整数数组和一个目标值,找出数组中和为目标值的两个数, 返回它们的索引。
你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。
比如:nums = [2, 7, 11, 15], target = 9.
因为 nums[0] + nums[1] = 2 + 7 = 9. 所以返回 [0, 1].
问题:数组中可以有重复的元素吗?
不能有重复的元素, 否则答案不唯一。 */
//时间复杂度:O(n)
//空间复杂度:O(n)
public class Ex2 {
public static void main(String[] args) {
int[] nums = {2, 7, 11, 15};
System.out.println(Arrays.toString(twoSum(nums, 9))); //数组输出语句
}
public static int[] twoSum (int[] arr, int target) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < arr.length; i++) {
if (map.containsKey(target - arr[i])) {
int j = map.get(target - arr[i]); // j < i
return new int[] {j,i};
} else {
map.put(arr[i], i);
}
}
return null;
}
}
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/*
给定一个字符串数组 words 和一个字符串 chars. 如果一个字符串能被 chars 里面的字符组成,那么这个字符串就是"好"的(chars里面每个字符只能使用一次)。
求:words 里面所有好的字符串的字符总个数。
比如:
words = ["cat", "bt", "hat", "tree"]
chars = "atach"
好的字符串有 "cat", "hat", 3 + 3 = 6.
输出:6
*/
public class HomeWork2 {
public int countCharacters(String[] words, String chars) {
Map<Character, Integer> map = createMap(chars);
int sum = 0;
for(String s : words) {
Map<Character, Integer> m = createMap(s);
if(canGenerate(m, map)) sum += s.length();
}
return sum;
}
private boolean canGenerate(Map<Character, Integer> m, Map<Character, Integer> map) {
Set<Map.Entry<Character, Integer>> entries = m.entrySet();
for(Map.Entry<Character, Integer> entry : entries) {
Character c = entry.getKey();
int cnt = entry.getValue();
if(!map.containsKey(c) || map.get(c) < cnt) return false;
}
return true;
}
private Map<Character, Integer> createMap(String chars) {
Map<Character, Integer> map = new HashMap<>();
for (int i = 0; i < chars.length(); i++) {
char c = chars.charAt(i);
if(map.containsKey(c)) map.put(c, map.get(c) + 1);
else map.put(c, 1);
}
return map;
}
// public static int charSum(String[] words, String chars) {
// HashSet<Character> set = new HashSet<>();
// int sum = 0;
// int flag = 0;
// for (int i = 0; i < chars.length(); i++) {
// set.add(chars.charAt(i));
// }
// for (int i = 0; i < words.length; i++) {
// for (int j = 0; j < words[i].length(); j++) {
// if(!set.contains(words[i].charAt(j))) {
// flag = 1;
// break;
// }
// }
// if(flag == 0)
// sum += words[i].length();
// else
// flag = 0;
// }
// return sum;
// }
public static void main(String[] args) {
String[] words = {"cat", "bt", "hat", "tree"};
String chars = "atach";
int sum = charSum(words, chars);
System.out.println(sum);
}
}
Properties(属性集) — 一般作为配置文件存在
概述
- Hashtable<Object, Object> 的子类 Hashtable 1.0就提供,泛型是1.5提供。所以设计有点问题
- Properties类表示了一个可持久的属性集
- Properties可以把数据保存到流中,或者从流中加载数据。保证其可持久
- Properties中每个键及其对应值都是一个字符串(所以不要使用Hashtable定义的方法添加键值对,因为可能插入不是String类型的键值对。如果一个Properties中有非String的键值对,这样的Properties是“不安全的”,调用store或者save方法会失败)
API
增(改):
Object setProperty(String key, String value) //properties提供方法,可以装入获取String类型的数据
Properties info = new Properties();
info.setProperty("刘强东", "章泽天");
info.setProperty("文章", "马伊利");
info.setProperty("王宝强", "马蓉");
info.setProperty("贾乃亮", "李小璐");
System.out.println(info.setProperty("罗志祥", "周扬青")); // null
System.out.println(info.setProperty("王宝强", "")); // 马蓉 。注:继承与Hashtable所以不能存null
删:
Object remove(Object key) // Hashtable提供的
查:
String getProperty(String key) // 避免使用Hashtable的get带来的强转麻烦,所以properties提供该方法
System.out.println(info.getProperty("刘强东")); // 章泽天
System.out.println(info.getProperty("罗志祥")); // null
String getProperty(String key, String defaultValue)
System.out.println(info.getProperty("刘强东", "default")); // 如果不存在,返回default,不返回null
System.out.println(info.getProperty("罗志祥", "default"));
遍历:
Set<String> stringPropertyNames() ---> keySet()
Set<String> names = info.stringPropertyNames();
for (String name : names) {
String value = info.getProperty(name);
System.out.println(name + "=" + value);
}
流相关:
// 注意事项:字节流默认使用 ISO08869-1 字符编码。
void store(OutputStream out, String comments) //不常用
void load(InputStream inStream) //不常用
Properties info = new Properties();
info.setProperty("刘强东", "章泽天");
info.setProperty("文章", "马伊利");
info.setProperty("王宝强", "马蓉");
info.setProperty("贾乃亮", "李小璐");
1.
void store(Writer writer, String comments)
try (Writer writer = new FileWriter("info.properties")) { // 使用IDEA默认的编码表
info.store(writer,"...") //comments是说明
} catch (IOException e) {
e.printStackTrace();
}
void load(Reader reader)
try (Reader reader = new FileReader("info.properties")) {
info.load(reader);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(info);
2. // 默认使用UTF-8字符编码
void storeToXML(OutputStream os, String comment)
try (OutputStream out = new FileOutputStream("info.xml")) {
info.storeToXML(out, "...");
} catch (IOException e) {
e.printStackTrace();
}
void loadFromXML(InputStream in)
try (InputStream in = new FileInputStream("info.xml")) {
info.loadFromXML(in);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(info);
练习
// 请设计一个猜数字小游戏,可以试玩5次。试玩结束之后,给出提示:游戏试玩结束,请付费。
Properties info = new Properties();
try (Reader reader = new FileReader("info.properties")) {
info.load(reader); //读取properties文件内容
int count = Integer.parseInt(info.getProperity("count")); //获取属性count的值,强转为int
if (count < 5) {
GuessNumberGame.start();
info.setProperty("count", ++count + ""); // 设置info内容
try (Writer writer = new FileWriter("info.properties")) { //try可以嵌套,可以被外层的catch捕获。
info.store(writer,"..."); // 写入
}
} else {
System.out.println("游戏试玩结束,请付费");
}
} catch (IOException e) {
e.printStackTrace();
}
class GuessNumberGame {
private GuessNumberGame(){ // 因为这个类只有一个静态方法,所以为了不让用户创建这个类,可以把构造方法写成private
}
public static void start() {
Random random = new Random();
Scanner sc = new Scanner(System.in);
int r = random.nextInt(100) + 1;
while (true) {
System.out.println("请输入您要猜的数字:");
int n = sc.nextInt();
if (n < r) System.out.println("您猜的数字" + n + "小了");
else if (n > r) System.out.println("您猜的数字" + n + "大了");
else {
System.out.println("恭喜您,猜中了!");
break;
}
}
}
}
/*给定两个字符串s和t, 它们只包含小写字母。字符串t是由s中的字母随机打乱之后,在随机的一个位置添加一个字母生成的。请找出那个添加的字母。
比如:
s = "abcd"
t = "baedc"
思路1:统计字符串s中每个字符出现的次数arr1(数组)
统计字符串t中每个字符出现的次数arr2(数组)
遍历数组,找到arr2[i]比arr1[1]大的索引。a + i
思路2:
a ^ a = 0
0 ^ a = a
a ^ b = b ^ a */
public static char findTheDifference(String s, String t) { // 思路二做法。异或性质
int xor = 0;
for (int i = 0; i < s.length(); i++) xor ^= s.charAt(i);
for (int i = 0; i < s.length(); i++) xor ^= s.charAt(i);
return (char) xor;
}
Map小结
Map
|-- HashMap
|-- LinkedHashMap
|-- Hashtable
|-- Properties
|-- TreeMap
更多推荐
已为社区贡献1条内容
所有评论(0)