Java春招面試複習:有關於Java Map,應該掌握的8個問題
前言
最近幾天看了幾篇有關於Java Map的外國博文,寫得非常不錯,所以整理了Java map 應該掌握的8個問題,都是日常開發司空見慣的問題,希望對大家有幫助;如果有不正確的地方,歡迎提出,萬分感謝哈~
1、如何把一個Map轉化為List
日常開發中,我們經常遇到這種場景,把一個Map轉化為List。map轉List有以下三種轉化方式:
- 把map的鍵key轉化為list
- 把map的值value轉化為list
- 把map的鍵值key-value轉化為list
虛擬碼如下:
// key list
List keyList = new ArrayList(map.keySet());
// value list
List valueList = new ArrayList(map.values());
// key-value list
List entryList = new ArrayList(map.entrySet());
示例程式碼:
public class Test {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(2, "jay");
map.put(1, "whx");
map.put(3, "huaxiao");
//把一個map的鍵轉化為list
List<Integer> keyList = new ArrayList<>(map.keySet());
System.out.println(keyList);
//把map的值轉化為list
List<String> valueList = new ArrayList<>(map.values());
System.out.println(valueList);
把map的鍵值轉化為list
List entryList = new ArrayList(map.entrySet());
System.out.println(entryList);
}
}
執行結果:
[1, 2, 3]
[whx, jay, huaxiao]
[1=whx, 2=jay, 3=huaxiao]
2、如何遍歷一個Map
我們經常需要遍歷一個map,可以有以下兩種方式實現:
通過entrySet+for實現遍歷
for(Entry entry: map.entrySet()) {
// get key
K key = entry.getKey();
// get value
V value = entry.getValue();
}
例項程式碼:
public class EntryMapTest {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(2, "jay");
map.put(1, "whx");
map.put(3, "huaxiao");
for(Map.Entry entry: map.entrySet()) {
// get key
Integer key = (Integer) entry.getKey();
// get value
String value = (String) entry.getValue();
System.out.println("key:"+key+",value:"+value);
}
}
}
通過Iterator+while實現遍歷
Iterator itr = map.entrySet().iterator();
while(itr.hasNext()) {
Entry entry = itr.next();
// get key
K key = entry.getKey();
// get value
V value = entry.getValue();
}
例項程式碼:
public class IteratorMapTest {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(2, "jay");
map.put(1, "whx");
map.put(3, "huaxiao");
Iterator itr = map.entrySet().iterator();
while(itr.hasNext()) {
Map.Entry entry = (Map.Entry) itr.next();
// get key
Integer key = (Integer) entry.getKey();
// get value
String value = (String) entry.getValue();
System.out.println("key:"+key+",value:"+value);
}
}
}
執行結果:
key:1,value:whx
key:2,value:jay
key:3,value:huaxiao
3、如何根據Map的keys進行排序
對Map的keys進行排序,在日常開發很常見,主要有以下兩種方式實現。
把Map.Entry放進list,再用Comparator對list進行排序
List list = new ArrayList(map.entrySet());
Collections.sort(list, (Entry e1, Entry e2)-> {
return e1.getKey().compareTo(e2.getKey());
});
例項程式碼:
public class SortKeysMapTest {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("2010", "jay");
map.put("1999", "whx");
map.put("3010", "huaxiao");
List<Map.Entry<String,String>> list = new ArrayList<>(map.entrySet());
Collections.sort(list, (Map.Entry e1, Map.Entry e2)-> {
return e1.getKey().toString().compareTo(e2.getKey().toString());
});
for (Map.Entry entry : list) {
System.out.println("key:" + entry.getKey() + ",value:" + entry.getValue());
}
}
}
使用SortedMap+TreeMap+Comparator實現
SortedMap sortedMap = new TreeMap(new Comparator() {
@Override
public int compare(K k1, K k2) {
return k1.compareTo(k2);
}
});
sortedMap.putAll(map);
例項程式碼:
public class SortKeys2MapTest {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("2010", "jay");
map.put("1999", "whx");
map.put("3010", "huaxiao");
SortedMap sortedMap = new TreeMap(new Comparator<String>() {
@Override
public int compare(String k1, String k2) {
return k1.compareTo(k2);
}
});
sortedMap.putAll(map);
Iterator itr = sortedMap.entrySet().iterator();
while(itr.hasNext()) {
Map.Entry entry = (Map.Entry) itr.next();
// get key
String key = (String) entry.getKey();
// get value
String value = (String) entry.getValue();
System.out.println("key:"+key+",value:"+value);
}
}
}
執行結果:
key:1999,value:whx
key:2010,value:jay
key:3010,value:huaxiao
4、如何對Map的values進行排序
List list = new ArrayList(map.entrySet());
Collections.sort(list, (Entry e1, Entry e2) ->{
return e1.getValue().compareTo(e2.getValue());
});
例項程式碼:
public class SortValuesMapTest {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("2010", "jay");
map.put("1999", "whx");
map.put("3010", "huaxiao");
List <Map.Entry<String,String>>list = new ArrayList<>(map.entrySet());
Collections.sort(list, (Map.Entry e1, Map.Entry e2)-> {
return e1.getValue().toString().compareTo(e2.getValue().toString());
}
);
for (Map.Entry entry : list) {
System.out.println("key:" + entry.getKey() + ",value:" + entry.getValue());
}
}
}
執行結果:
key:3010,value:huaxiao
key:2010,value:jay
key:1999,value:whx
5、如何初始化一個靜態/不可變的Map
初始化一個靜態不可變的map,單單static final+static程式碼還是不行的,如下:
public class Test1 {
private static final Map <Integer,String>map;
static {
map = new HashMap<Integer, String>();
map.put(1, "one");
map.put(2, "two");
}
public static void main(String[] args) {
map.put(3, "three");
Iterator itr = map.entrySet().iterator();
while(itr.hasNext()) {
Map.Entry entry = (Map.Entry) itr.next();
// get key
Integer key = (Integer) entry.getKey();
// get value
String value = (String) entry.getValue();
System.out.println("key:"+key+",value:"+value);
}
}
}
這裡面,map繼續新增元素(3,“three”),發現是OK的,執行結果如下:
key:1,value:one
key:2,value:two
key:3,value:three
真正實現一個靜態不可變的map,需要Collections.unmodifiableMap,程式碼如下:
public class Test2 {
private static final Map<Integer, String> map;
static {
Map<Integer,String> aMap = new HashMap<>();
aMap.put(1, "one");
aMap.put(2, "two");
map = Collections.unmodifiableMap(aMap);
}
public static void main(String[] args) {
map.put(3, "3");
Iterator itr = map.entrySet().iterator();
while(itr.hasNext()) {
Map.Entry entry = (Map.Entry) itr.next();
// get key
Integer key = (Integer) entry.getKey();
// get value
String value = (String) entry.getValue();
System.out.println("key:"+key+",value:"+value);
}
}
}
執行結果如下:
可以發現,繼續往map新增元素是會報錯的,實現真正不可變的map。
6、HashMap, TreeMap, and Hashtable,ConcurrentHashMap的區別
HashMap | TreeMap | Hashtable | ConcurrentHashMap | |
---|---|---|---|---|
有序性 | 否 | 是 | 否 | 否 |
null k-v | 是-是 | 否-是 | 否-否 | 否-否 |
線性安全 | 否 | 否 | 是 | 是 |
時間複雜度 | O(1) | O(log n) | O(1) | O(log n) |
底層結構 | 陣列+連結串列+紅黑樹 | 紅黑樹 | 陣列+連結串列 | 陣列+連結串列+紅黑樹 |
7、如何建立一個空map
如果map是不可變的,可以這樣建立:
Map map=Collections.emptyMap();
or
Map<String,String> map=Collections.<String, String>emptyMap();
//map1.put("1", "1"); 執行出錯
如果你希望你的空map可以新增元素的,可以這樣建立
Map map = new HashMap();
8、有關於map的複製
有關於hashmap的複製,在日常開發中,使用也比較多。主要有java=,clone,putAll
,但是他們都是淺複製,使用的時候注意啦,可以看一下以下例子:
例子一,使用=複製一個map:
public class CopyMapAssignTest {
public static void main(String[] args) {
Map<Integer, User> userMap = new HashMap<>();
userMap.put(1, new User("jay", 26));
userMap.put(2, new User("fany", 25));
//Shallow clone
Map<Integer, User> clonedMap = userMap;
//Same as userMap
System.out.println(clonedMap);
System.out.println("\nChanges reflect in both maps \n");
//Change a value is clonedMap
clonedMap.get(1).setName("test");
//Verify content of both maps
System.out.println(userMap);
System.out.println(clonedMap);
}
}
執行結果:
{1=User{name='jay', age=26}, 2=User{name='fany', age=25}}
Changes reflect in both maps
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}
從執行結果看出,對cloneMap修改,兩個map都改變了,所以=是淺複製。
例子二,使用hashmap的clone複製:
public class CopyCloneMapTest {
public static void main(String[] args) {
HashMap<Integer, User> userMap = new HashMap<>();
userMap.put(1, new User("jay", 26));
userMap.put(2, new User("fany", 25));
//Shallow clone
HashMap<Integer, User> clonedMap = (HashMap<Integer, User>) userMap.clone();
//Same as userMap
System.out.println(clonedMap);
System.out.println("\nChanges reflect in both maps \n");
//Change a value is clonedMap
clonedMap.get(1).setName("test");
//Verify content of both maps
System.out.println(userMap);
System.out.println(clonedMap);
}
}
執行結果:
{1=User{name='jay', age=26}, 2=User{name='fany', age=25}}
Changes reflect in both maps
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}
從執行結果看出,對cloneMap修改,兩個map都改變了,所以hashmap的clone也是淺複製。
例子三,通過putAll操作
public class CopyPutAllMapTest {
public static void main(String[] args) {
HashMap<Integer, User> userMap = new HashMap<>();
userMap.put(1, new User("jay", 26));
userMap.put(2, new User("fany", 25));
//Shallow clone
HashMap<Integer, User> clonedMap = new HashMap<>();
clonedMap.putAll(userMap);
//Same as userMap
System.out.println(clonedMap);
System.out.println("\nChanges reflect in both maps \n");
//Change a value is clonedMap
clonedMap.get(1).setName("test");
//Verify content of both maps
System.out.println(userMap);
System.out.println(clonedMap);
}
}
執行結果:
{1=User{name='jay', age=26}, 2=User{name='fany', age=25}}
Changes reflect in both maps
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}
從執行結果看出,對cloneMap修改,兩個map都改變了,所以putAll還是淺複製。
那麼,如何實現深度複製呢?
可以使用序列化實現,如下為谷歌Gson序列化HashMap,實現深度複製的例子:
public class CopyDeepMapTest {
public static void main(String[] args) {
HashMap<Integer, User> userMap = new HashMap<>();
userMap.put(1, new User("jay", 26));
userMap.put(2, new User("fany", 25));
//Shallow clone
Gson gson = new Gson();
String jsonString = gson.toJson(userMap);
Type type = new TypeToken<HashMap<Integer, User>>(){}.getType();
HashMap<Integer, User> clonedMap = gson.fromJson(jsonString, type);
//Same as userMap
System.out.println(clonedMap);
System.out.println("\nChanges DO NOT reflect in other map \n");
//Change a value is clonedMap
clonedMap.get(1).setName("test");
//Verify content of both maps
System.out.println(userMap);
System.out.println(clonedMap);
}
}
執行結果:
{1=User{name='jay', age=26}, 2=User{name='fany', age=25}}
Changes DO NOT reflect in other map
{1=User{name='jay', age=26}, 2=User{name='fany', age=25}}
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}
從執行結果看出,對cloneMap修改,userMap沒有被改變,所以是深度複製。
相關文章
- Java春招面試複習:執行緒池解析Java面試執行緒
- Java春招面試複習:Java反射的入門到實踐,再到原理Java面試反射
- java中關於Map的九大問題Java
- 40個Java集合面試問題和答案,面試奇葩問題,你掌握了嗎?Java面試
- Java面試必問面試題,你掌握了嗎?Java面試題
- 一個關於Java Excel的問題JavaExcel
- 關於 Java 8 的6大頭疼問題Java
- Java面試中與原始碼有關的問題分享Java面試原始碼
- java map存取重複值、幼兒園分班問題、map按key自動排序問題Java排序
- Java面試常問的幾個問題Java面試
- java泛型應該注意的問題。Java泛型
- JAVA面試題(8)Java面試題
- 一個關於java.net.URL的問題.Java
- 關於Java面試,你應該準備這些知識點Java面試
- 簡單問題:JAVA物件的淺複製,有一個疑問!Java物件
- Java 面試題關於方法的重寫Java面試題
- 有關使用java -Xrunhprof的問題Java
- JAVA後端秋招/春招準備方向Java後端
- 關於java的“原子操作”問題Java
- 關於Integer面試的一個問題面試
- Java Thread應該注意的問題 (轉)Javathread
- 關於學習java中的按位取反(~)的問題Java
- 我是如何進入阿里巴巴的-面向春招應屆生Java面試指南(一)阿里Java面試
- Java 8 Streams map()Java
- Java秋招校招面試Java面試
- 【Java8新特性】關於Java8中的日期時間API,你需要掌握這些!!JavaAPI
- java面試問題Java面試
- 學習 MySQL 應該掌握的 6 個技巧MySql
- 【Java面試題】如何回答GC相關問題Java面試題GC
- Java中關於String型別的10個問題Java型別
- 【8】進大廠必須掌握的面試題-Java面試-異常和執行緒面試題Java執行緒
- 【Java】幾道常見的秋招面試題Java面試題
- 每個 Java 開發者應該知道(並愛上)的 8 個工具Java
- 春招面試(馭勢科技)面試
- 【Java面試題】34 List 、Map、Set 區別?Java面試題
- 你應該知道的10件關於Java 6的事情Java
- 新手程式設計師該如何準備面試?【備戰春招/秋招系列】程式設計師面試
- 【原創】關於JAVA複習的最佳敏捷實踐Java敏捷