回答編集履歴

1

ジェネリクスへの理解の勘違い?

2018/03/05 18:28

投稿

swordone
swordone

スコア20651

test CHANGED
@@ -1,3 +1,93 @@
1
+ > ドキュメントを調べてみるとMapインターフェースの引数はMap<K, V>と書いてありました。実際に利用する場合はMap<Integer, String>だったりMap<String, Integer>だったりと多様性があるはずと記憶していたのでエラーの原因がわかりません。
2
+
3
+
4
+
5
+ ひょっとしてジェネリクスのことを大いに勘違いしている?
6
+
7
+ Map<K, V>というのは、使うときや作るときにK,Vに具体的な型の名前を入れることで、
8
+
9
+ メソッドの対応する引数型や返り値型を制限する機能です。
10
+
11
+ putメソッドは引数がput(K, V)と指定されており、getメソッドの返り値はVとされていますが、
12
+
13
+ これがジェネリクスによってインスタンスごとに制限されます。
14
+
15
+ ```java
16
+
17
+ Map<Integer, String> map = new HashMap<Integer, String>();
18
+
19
+ /*
20
+
21
+ * K=Integer, V=Stringなので、このインスタンスに対するputメソッドは
22
+
23
+ * put(Integer, String)として扱われる。
24
+
25
+ * getメソッドの返り値はV、つまりStringとして扱われる。
26
+
27
+ */
28
+
29
+ map.put(1, "A"); // OK
30
+
31
+ //map.put("1", "A"); // NG Integerを要求する第1引数に"1"というStringは入れられない
32
+
33
+ String s = map.get(1); // OK getメソッドの返り値はV、つまりStringなのでString型変数に入れられる
34
+
35
+ // Integer i = map.get(1); // NG String型の返り値をInteger型の変数に入れることはできない
36
+
37
+
38
+
39
+ Map<String, Integer> map2 = new HashMap<String, Integer>();
40
+
41
+ /*
42
+
43
+ * K=String, V=Integerなので、このインスタンスに対するputメソッドは
44
+
45
+ * put(String, Integer)として扱われる。
46
+
47
+ * getメソッドの返り値はV、つまりIntegerとして扱われる。
48
+
49
+ */
50
+
51
+ map.put("A", 1); // OK
52
+
53
+ //map.put("A", "1"); // NG Integerを要求する第2引数に"1"というStringは入れられない
54
+
55
+ Integer s = map.get("A"); // OK getメソッドの返り値はV、つまりIntegerなのでInteger型変数に入れられる
56
+
57
+ // String i = map.get("A"); // NG Integer型の返り値をString型の変数に入れることはできない
58
+
59
+ ```
60
+
61
+ 同じMapという型でも、ジェネリクスが違うとこのように型に関して大きく異なる挙動をします。
62
+
63
+ これらが同じ型として扱われると非常に扱いづらいうえ、型安全という点でも危険です。
64
+
65
+ このため、ジェネリクスが違う型同士では代入できないのです。上記例でいえば、
66
+
67
+ ```java
68
+
69
+ /*
70
+
71
+ * NG 左辺はMap<Integer, String>, 右辺はMap<String, Integer>
72
+
73
+ * 扱う型が異なるため代入できない
74
+
75
+ */
76
+
77
+ // map = map2
78
+
79
+ ```
80
+
81
+
82
+
83
+ ---
84
+
85
+
86
+
87
+ 以下、Streamの型について言っていると思って最初に回答したもの
88
+
89
+
90
+
1
91
  ```java
2
92
 
3
93
  Map<Integer, List<Student>> map = students.stream()