参考答案
Map接口定义的集合又称查找表,用于存储所谓“Key-Value”映射对。Key可以看成是Value的索引,作为Key的对象在集合中不可以重复。
现有字符串"good good study, day day up.",统计其中各个字符出现的次数。例如:上述字符串中各个字符的出现的次数为:{g=2, u=2, d=5, t=1, s=1, p=1, a=2, o=4, y=3}。
参考答案
实现此案例需要按照如下步骤进行。
步骤一:新建Summary类,添加测试方法test1方法
首先,在工程JavaSE的day05包下新建类Summary;然后,在该类中添加方法test1,代码如下所示:
package day05; import org.junit.Test; public class Summary { /** * 统计一句话中字符的个数 */ @Test public void test1() { } }
步骤二:去除字符串中的空格
使用String类的replaceAll方法,将字符串"good good study, day day up."中的空格使用空字符串替换掉,代码如下所示:
package day05; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.junit.Test; public class Summary { /** * 统计一句话中字符的个数 */ @Test public void test1() { #cold_bold String line = "good good study, day day up."; #cold_bold line = line.replaceAll("[^a-zA-Z]+", ""); } }
步骤三:使用Map,获取各个字符的个数
首先,构建map对象,该map对象的key存储字符串中的各个字符,value存储各个字符对应的个数。
然后,构建循环,循环的次数为去除空格后的字符串长度;在循环中,使用String类的charAr方法获取到i位置的字符,接着,使用Map的constainsKey方法判断刚刚获取到字符是否存在于Map的key中,如果存在,则用该字符作为key,使用Map的get方法取出对应的value,并将该value值加1,重新存储到map中;如果,不存在,则将该获取到字符作为key,value值为1,存储到map中。
最后,输出map对象,可以看到字符串中各个字符的个数,代码如下所示:
package day05; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.junit.Test; public class Summary { /** * 统计一句话中字符的个数 */ @Test public void test1() { String line = "good good study, day day up."; #cold_bold line = line.replaceAll("[^a-zA-Z]+", ""); #cold_bold Map<Character, Integer> map = new HashMap<Character, Integer>(); #cold_bold for (int i = 0; i < line.length(); i++) { #cold_bold char c = line.charAt(i); #cold_bold if (map.containsKey(c)) { #cold_bold map.put(c, map.get(c) + 1); #cold_bold } else { #cold_bold map.put(c, 1); #cold_bold } #cold_bold } #cold_bold System.out.println(map); } }
本案例的完整代码如下所示:
package day05; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.junit.Test; public class Summary { /** * 统计一句话中字符的个数 */ @Test public void test1() { String line = "good good study, day day up."; line = line.replaceAll("[^a-zA-Z]+", ""); Map<Character, Integer> map = new HashMap<Character, Integer>(); for (int i = 0; i < line.length(); i++) { char c = line.charAt(i); if (map.containsKey(c)) { map.put(c, map.get(c) + 1); } else { map.put(c, 1); } } System.out.println(map); } }
参考答案
以java.lang.Object来理解,JVM每实例化一个Object,它都会将这个Object放入到一个Hash哈希表中去,这样的话,下次做Object的比较或者取这个对象的时候,它会根据对象的hashCode再从Hash表中取这个对象。这样做的目的是提高取对象的效率。具体过程如下:
1) new Object(),JVM根据这个对象的hashCode值,放入到对应的Hash表对应的Key上,如果不同的对象产生了相同的hash值,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同hashCode的对象放到这个单链表上去,串在一起,就是Hash桶。
2) 比较两个对象的时候,首先根据他们的hashCode去hash表中找它的对象,当两个对象的hashCode相同,也就是说这两个对象放在Hash表中的同一个key上,则他们一定在这个key上的链表上。那么此时就只能根据Object的equals方法来比较这个对象是否相等。当两个对象的hashCode不同时,则这两个对象一定不能相等。
现有1000万个对象,需用使用HashMap进行存储。使用如下代码构建HashMap对象:
Map map=new HashMap();
上述代码构建的map,存在效率问题,应如何进行优化。
参考答案
优化后的代码为:
Map map=new HashMap(10000000);
构建HashMap时,默认构造方法的初始容量为16,现要存储1000万个对象,将初始容量设置为1000万。加载因子应然为默认的0.75, 0.75是性能和空间相对平衡结果。 在创建散列表时候指定合理容量, 减少rehash提高性能。
参考答案
当处理Map集合中每个元素的时候,需要迭代Map集合。Map有两种常见的迭代方式: 迭代Key, 迭代Entry。
方式一:迭代Key,请看如下代码:
map = ....//初始化map Set<Character> keySet = map.keySet(); for (Iterator<Character> i = keySet.iterator(); i.hasNext();) { Character key = i.next(); Integer value = map.get(key); System.out.println(key+":"+value); }
上述代码中,使用了迭代Key的方式,实现了迭代Map对象。使用迭代Key方式,关键的方法为Map的keySet方法,该方法获取到Map对象中所有的Key对应的Set集合。接下来,遍历Set集合,获取到每一个Key,然后,使用Map的get方法获取到Key对应的Value。
方式二:迭代Entry,请看如下代码:
map = ....//初始化map Set<Entry<Character, Integer>> entries=map.entrySet(); for (Entry<Character, Integer> e : entries) { Character key = e.getKey(); Integer value = e.getValue(); System.out.println(key+":"+value); }
上述代码中,使用了迭代Entry的方式,实现了迭代Map对象。使用迭代Entry方式,关键的方法为Map的entrySet方法,该方法将Map对象中每一个key,value设置为一个Entry对象,再存储到Set中,因此该方法返回Set集合。循环Set集合,在循环中使用Entry的getKey和getValue方法,获取到每一个Key-Value对。
在“统计一句话中重复字符的个数”案例的基础上,分别使用迭代Key的方式和迭代Entry的方式遍历集合map。
参考答案
实现此案例需要按照如下步骤进行。
步骤一:构建测试方法
在Summary类中添加测试方法test2,使test2中的代码和test1中的代码保持一致,代码如下所示:
package day05; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.junit.Test; public class Summary { //...(之前案例的代码,略) #cold_bold /** #cold_bold * 使用迭代key的方式遍历map集合 #cold_bold */ #cold_bold @Test #cold_bold public void test2() { #cold_bold String line = "good good study, day day up."; #cold_bold line = line.replaceAll("[^a-zA-Z]+", ""); #cold_bold Map<Character, Integer> map = new HashMap<Character, Integer>(); #cold_bold for (int i = 0; i < line.length(); i++) { #cold_bold char c = line.charAt(i); #cold_bold if (map.containsKey(c)) { #cold_bold map.put(c, map.get(c) + 1); #cold_bold } else { #cold_bold map.put(c, 1); #cold_bold } #cold_bold } #cold_bold } }
步骤二:使用迭代key的方式遍历集合map
使用迭代key的方式遍历集合map,代码如下所示:
package day05; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.junit.Test; public class Summary { //...(之前案例的代码,略) /** * 使用迭代key的方式遍历map集合 */ @Test public void test2() { String line = "good good study, day day up."; line = line.replaceAll("[^a-zA-Z]+", ""); Map<Character, Integer> map = new HashMap<Character, Integer>(); for (int i = 0; i < line.length(); i++) { char c = line.charAt(i); if (map.containsKey(c)) { map.put(c, map.get(c) + 1); } else { map.put(c, 1); } } #cold_bold Set<Character> keys = map.keySet(); #cold_bold for (Character key : keys) { #cold_bold System.out.println(key + ":" + map.get(key)); #cold_bold } } }
步骤三:构建测试方法
在Summary类中添加测试方法test3,使test3中的代码和test1中的代码保持一致,代码如下所示:
package day05; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.junit.Test; public class Summary { //...(之前案例的代码,略) /** * 使用迭代key的方式遍历map集合 */ @Test public void test2() { String line = "good good study, day day up."; line = line.replaceAll("[^a-zA-Z]+", ""); Map<Character, Integer> map = new HashMap<Character, Integer>(); for (int i = 0; i < line.length(); i++) { char c = line.charAt(i); if (map.containsKey(c)) { map.put(c, map.get(c) + 1); } else { map.put(c, 1); } } Set<Character> keys = map.keySet(); for (Character key : keys) { System.out.println(key + ":" + map.get(key)); } } #cold_bold /** #cold_bold * 使用迭代Entry的方式遍历map集合 #cold_bold */ #cold_bold @Test #cold_bold public void test3() { #cold_bold String line = "good good study, day day up."; #cold_bold line = line.replaceAll("[^a-zA-Z]+", ""); #cold_bold Map<Character, Integer> map = new HashMap<Character, Integer>(); #cold_bold for (int i = 0; i < line.length(); i++) { #cold_bold char c = line.charAt(i); #cold_bold if (map.containsKey(c)) { #cold_bold map.put(c, map.get(c) + 1); #cold_bold } else { #cold_bold map.put(c, 1); #cold_bold } #cold_bold } #cold_bold } #cold_bold} }
步骤四:使用迭代Entry的方式迭代集合map
使用迭代Entry的方式迭代集合map,代码如下所示:
package day05; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.junit.Test; public class Summary { //...(之前案例的代码,略) /** * 使用迭代key的方式遍历map集合 */ @Test public void test2() { String line = "good good study, day day up."; line = line.replaceAll("[^a-zA-Z]+", ""); Map<Character, Integer> map = new HashMap<Character, Integer>(); for (int i = 0; i < line.length(); i++) { char c = line.charAt(i); if (map.containsKey(c)) { map.put(c, map.get(c) + 1); } else { map.put(c, 1); } } Set<Character> keys = map.keySet(); for (Character key : keys) { System.out.println(key + ":" + map.get(key)); } } /** * 使用迭代Entry的方式遍历map集合 */ @Test public void test3() { String line = "good good study, day day up."; line = line.replaceAll("[^a-zA-Z]+", ""); Map<Character, Integer> map = new HashMap<Character, Integer>(); for (int i = 0; i < line.length(); i++) { char c = line.charAt(i); if (map.containsKey(c)) { map.put(c, map.get(c) + 1); } else { map.put(c, 1); } } #cold_bold Set<Map.Entry<Character, Integer>> entrys = map.entrySet(); #cold_bold for (Map.Entry<Character, Integer> entry : entrys) { #cold_bold System.out.println(entry.getKey() + ":" + entry.getValue()); #cold_bold } } }
本案例的完整代码如下所示:
package day05; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.junit.Test; public class Summary { //...(之前案例的代码,略) @Test public void test2() { String line = "good good study, day day up."; line = line.replaceAll("[^a-zA-Z]+", ""); Map<Character, Integer> map = new HashMap<Character, Integer>(); for (int i = 0; i < line.length(); i++) { char c = line.charAt(i); if (map.containsKey(c)) { map.put(c, map.get(c) + 1); } else { map.put(c, 1); } } Set<Character> keys = map.keySet(); for (Character key : keys) { System.out.println(key + ":" + map.get(key)); } } @Test public void test3() { String line = "good good study, day day up."; line = line.replaceAll("[^a-zA-Z]+", ""); Map<Character, Integer> map = new HashMap<Character, Integer>(); for (int i = 0; i < line.length(); i++) { char c = line.charAt(i); if (map.containsKey(c)) { map.put(c, map.get(c) + 1); } else { map.put(c, 1); } } Set<Map.Entry<Character, Integer>> entrys = map.entrySet(); for (Map.Entry<Character, Integer> entry : entrys) { System.out.println(entry.getKey() + ":" + entry.getValue()); } } }
在“统计一句话中重复单词的个数——遍历结果”案例的基础上,按照字符放入map中的顺序遍历map。
参考答案
实现此案例需要按照如下步骤进行。
步骤一:将HashMap改成LinkedHashMap
首先,构建测试方法test4、test5;然后,复制test2的代码到test4中,复制test3的代码到test5中,最后,将test4、test5中构建map对象的实现类改成LinkedHashMap,代码如下所示:
package day05; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import org.junit.Test; public class Summary { //...(之前案例的代码,略) /** * 按照字符在字符串中出现的顺序显示集合 */ @Test public void test4() { String line = "good good study, day day up."; line = line.replaceAll("[^a-zA-Z]+", ""); #cold_bold Map<Character, Integer> map = new LinkedHashMap<Character, Integer>(); for (int i = 0; i < line.length(); i++) { char c = line.charAt(i); if (map.containsKey(c)) { map.put(c, map.get(c) + 1); } else { map.put(c, 1); } } Set<Character> keys = map.keySet(); for (Character key : keys) { System.out.println(key + ":" + map.get(key)); } } /** * 按照字符在字符串中出现的顺序显示集合 */ @Test public void test5() { String line = "good good study, day day up."; line = line.replaceAll("[^a-zA-Z]+", ""); #cold_bold Map<Character, Integer> map = new LinkedHashMap<Character, Integer>(); for (int i = 0; i < line.length(); i++) { char c = line.charAt(i); if (map.containsKey(c)) { map.put(c, map.get(c) + 1); } else { map.put(c, 1); } } Set<Map.Entry<Character, Integer>> entrys = map.entrySet(); for (Map.Entry<Character, Integer> entry : entrys) { System.out.println(entry.getKey() + ":" + entry.getValue()); } } }
上述代码中的LinkedHashMap是Map 接口的哈希表和链表实现,具有可预知的迭代顺序。此实现与 HashMap 的不同之处在于,LinkedHashMap维护着一个双向循环链表。此链表定义了迭代顺序,该迭代顺序通常就是存放元素的顺序。
本案例的完整代码如下所示:
package day05; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import org.junit.Test; public class Summary { //...(之前案例的代码,略) /** * 按照字符在字符串中出现的顺序显示集合 */ @Test public void test4() { String line = "good good study, day day up."; line = line.replaceAll("[^a-zA-Z]+", ""); Map<Character, Integer> map = new LinkedHashMap<Character, Integer>(); for (int i = 0; i < line.length(); i++) { char c = line.charAt(i); if (map.containsKey(c)) { map.put(c, map.get(c) + 1); } else { map.put(c, 1); } } Set<Character> keys = map.keySet(); for (Character key : keys) { System.out.println(key + ":" + map.get(key)); } } /** * 按照字符在字符串中出现的顺序显示集合 */ @Test public void test5() { String line = "good good study, day day up."; line = line.replaceAll("[^a-zA-Z]+", ""); Map<Character, Integer> map = new LinkedHashMap<Character, Integer>(); for (int i = 0; i < line.length(); i++) { char c = line.charAt(i); if (map.containsKey(c)) { map.put(c, map.get(c) + 1); } else { map.put(c, 1); } } Set<Map.Entry<Character, Integer>> entrys = map.entrySet(); for (Map.Entry<Character, Integer> entry : entrys) { System.out.println(entry.getKey() + ":" + entry.getValue()); } } }
使用查看当前工程下demo文件夹下HelloWorld.txt文件的大小。
参考答案
实现此案例需要按照如下步骤进行。
步骤一:导入commons-io包
在工程JavaSE中,导入commons-io的jar包,以使用其中提供的类。
步骤二:新建类及测试方法
首先,在day05包下新建类CommonsFile,并在该类中新建测试方法testSizeOf,代码如下所示:
package day05; import org.junit.Test; public class CommonsFile { /** * 使用Commons-io API查看一个文件的大小 */ @Test public void testSizeOf(){ } }
步骤三:获取HelloWorld.txt文件大小
首先,使用File类构建表示当前工程下的demo文件夹下的HelloWorld.txt文件的对象file;然后,使用FileUtils类的sizeOf方法获取该文件的大小并输出,代码如下所示:
package day05; import java.io.File; import org.apache.commons.io.FileUtils; import org.junit.Test; public class CommonsFile { /** * 使用Commons-io API查看一个文件的大小 */ @Test public void testSizeOf(){ #cold_bold File file = new File("demo" + File.separator + "HelloWorld.txt"); #cold_bold long size=FileUtils.sizeOf(file); #cold_bold System.out.println(size); } }
步骤四:运行
运行testSizeOf方法,控制台输出结果如下所示:
demo\HelloWorld.txt占用字节量:0
这只因为,当前工程下并不存在demo文件夹,那就更没有HelloWorld.txt文件的存在了,因此占用字节长度为0。现在,在当前工程下创建demo文件夹,然后,在该文件夹下创建文件HelloWorld.txt并将该文件内容改为“hello”,再次运行testSizeOf方法,控制台输出结果如下所示:
demo\HelloWorld.txt占用字节量:5
本案例的完整代码如下所示:
package day05; import java.io.File; import org.apache.commons.io.FileUtils; import org.junit.Test; public class CommonsFile { /** * 使用Commons-io API查看一个文件的大小 */ @Test public void testSizeOf(){ File file = new File("demo" + File.separator + "HelloWorld.txt"); long size=FileUtils.sizeOf(file); System.out.println(size); } }
使用commons-io API,查看当前工程下src目录的大小。
参考答案
实现此案例需要按照如下步骤进行。
步骤一:新建类及测试方法
首先,在类CommonsFile中新建测试方法testSizeOfDirectory,代码如下所示:
package day05; import java.io.File; import org.apache.commons.io.FileUtils; import org.junit.Test; public class CommonsFile { //...(之前案例的代码,略) /** * 使用Commons-io API查看一个目录的大小 */ @Test public void testSizeOfDirectory(){ File file = new File("src"); long size=FileUtils.sizeOfDirectory(file); System.out.println(size); } }
步骤二:获取HelloWorld.txt文件大小
首先,使用File类构建表示当前工程下的src目录的对象file;然后,使用FileUtils类的sizeOfDirectory方法获取该目录的大小并输出,代码如下所示:
package day05; import java.io.File; import org.apache.commons.io.FileUtils; import org.junit.Test; public class CommonsFile { //...(之前案例的代码,略) /** * 使用Commons-io API查看一个目录的大小 */ @Test public void testSizeOfDirectory(){ File file = new File("src"); long size=FileUtils.sizeOfDirectory(file); System.out.println(size); } }
上述代码中的sizeOfDirectory方法,该方法会递归计算该目录下的所有文件的大小。
步骤三:运行
运行testSizeOfDirectory方法,到控制台查看输出结果,即为src目录的大小。
本案例的完整代码如下所示:
package day05; import java.io.File; import org.apache.commons.io.FileUtils; import org.junit.Test; public class CommonsFile { //...(之前案例的代码,略) /** * 使用Commons-io API查看一个目录的大小 */ @Test public void testSizeOfDirectory(){ File file = new File("src"); long size=FileUtils.sizeOfDirectory(file); System.out.println(size); } }
使用commons-io API,在当前工程下,创建a目录,然后在a目录下创建b目录,最后在b目录下创建c目录。
参考答案
实现此案例需要按照如下步骤进行。
步骤一:构建测试方法
首先,在CommonsFile类中新建测试方法testForceMkdir,代码如下所示:
package day05; import java.io.File; import java.io.IOException; import org.apache.commons.io.FileUtils; import org.junit.Test; public class CommonsFile { //...(之前案例的代码,略) #cold_bold /** #cold_bold *使用commons-io API创建多级目录 #cold_bold * @throws IOException #cold_bold */ #cold_bold @Test #cold_bold public void testForceMkdir() throws IOException{ #cold_bold #cold_bold } }
步骤二:创建多级目录
首先,使用File类构建表示当前工程下的多级目录a,b,c;然后,使用FileUtil类的forceMkdir方法创建多级目录,代码如下所示:
package day05; import java.io.File; import java.io.IOException; import org.apache.commons.io.FileUtils; import org.junit.Test; public class CommonsFile { //...(之前案例的代码,略) /** *使用commons-io API创建多级目录 * @throws IOException */ @Test public void testForceMkdir() throws IOException{ #cold_bold File dir = new File("a" + File.separator + "b" + File.separator + "c"); #cold_bold FileUtils.forceMkdir(dir); } }
步骤三:运行
运行forceMkdir方法,会发现工程下多了一个a文件夹,并且a文件夹下有b文件夹,b文件夹下有c文件夹。
本案例的完整代码如下所示:
package day05; import java.io.File; import java.io.IOException; import org.apache.commons.io.FileUtils; import org.junit.Test; public class CommonsFile { //...(之前案例的代码,略) /** *使用commons-io API创建多级目录 * @throws IOException */ @Test public void testForceMkdir() throws IOException{ File dir = new File("a" + File.separator + "b" + File.separator + "c"); FileUtils.forceMkdir(dir); } }
删除上一案例中创建的a目录及其子目录。
参考答案
实现此案例需要按照如下步骤进行。
步骤一:构建测试方法
首先,在CommonsFile类中新建测试方法testDeleteDirectory,代码如下所示:
package day05; import java.io.File; import java.io.IOException; import org.apache.commons.io.FileUtils; import org.junit.Test; public class CommonsFile { //...(之前案例的代码,略) /** *使用Commons-io API 实现删除目录及其内容 */ @Test public void testDeleteDirectory() throws IOException{ File dir = new File("a"); FileUtils.deleteDirectory(dir); } }
步骤二:删除目录
首先,使用File类构建表示当前工程下的a目录的对象file;然后,使用FileUtils类的deleteDirectory方法删除该目录,代码如下所示:
package day05; import java.io.File; import java.io.IOException; import org.apache.commons.io.FileUtils; import org.junit.Test; public class CommonsFile { //...(之前案例的代码,略) /** *使用Commons-io API 实现删除目录及其内容 */ @Test public void testDeleteDirectory() throws IOException{ #cold_bold File dir = new File("a"); #cold_bold FileUtils.deleteDirectory(dir); } }
步骤三:运行
运行testDeleteDirectory方法,会发现a目录不存在了。
本案例的完整代码如下所示:
package day05; import java.io.File; import java.io.IOException; import org.apache.commons.io.FileUtils; import org.junit.Test; public class CommonsFile { //...(之前案例的代码,略) /** *使用Commons-io API 实现删除目录及其内容 */ @Test public void testDeleteDirectory() throws IOException{ File dir = new File("a"); FileUtils.deleteDirectory(dir); } }