回答編集履歴
3
用語の誤りを訂正
test
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
**Javaの世界**
|
6
6
|
|
7
|
-
Javaコンパイラはtestの引数の型Set<CharSequence>とSet<String>は別の型とみなします(
|
7
|
+
Javaコンパイラはtestの引数の型Set<CharSequence>とSet<String>は別の型とみなします(非変)。testメソッドのシグネチャ(メソッド名と引数の型で決まる)はそれぞれ異なるので、メソッドがオーバーロードされています。
|
8
8
|
|
9
9
|
- Aのメソッド ... List<Number> test(Set<CharSequence>)
|
10
10
|
- Bのメソッド ... ArrayList<Integer> test(Set<String>)
|
@@ -33,12 +33,12 @@
|
|
33
33
|
・メソッドの戻り値の型が同一型か共変型(サブクラス、またはインターフェイスを実装するクラス)
|
34
34
|
・メソッドのアクセスレベルが同じか緩い
|
35
35
|
|
36
|
-
まずtestの戻り値が同一型か共変(variant)型かです。
|
36
|
+
まずtestの戻り値が同一型か共変(covariant)型かです。
|
37
37
|
ArrayListはListを実装するので共変型
|
38
38
|
|
39
|
-
ところがジェネリクスを適用
|
39
|
+
ところがジェネリクスを適用、コレクションが共変でも型パラメータが異なると非変(異なる型)になります。
|
40
|
-
ArrayList<Integer>とList<Number>は
|
40
|
+
ArrayList<Integer>とList<Number>は非変(nonvariant)
|
41
|
-
Set<Number>とSet<Integer>は
|
41
|
+
Set<Number>とSet<Integer>は非変
|
42
42
|
|
43
43
|
従って、Javaの世界ではメソッドの引数の型が異なるのでオーバーロード
|
44
44
|
しかし、JVMの世界ではオーバーライド(ArrayListはListを実装するので共変型)
|
2
冗長な部分を簡潔に
test
CHANGED
@@ -28,8 +28,6 @@
|
|
28
28
|
|
29
29
|
【メソッドのオーバーライドについて(追記)】
|
30
30
|
|
31
|
-
メソッドのオーバーライドが質問の主題なので解説します。
|
32
|
-
|
33
31
|
メソッドがオーバーライド可能な条件
|
34
32
|
・メソッドのシグネチャが同一(メソッド名が同じ,メソッドの引数が同じ型で並びが同一)
|
35
33
|
・メソッドの戻り値の型が同一型か共変型(サブクラス、またはインターフェイスを実装するクラス)
|
@@ -40,12 +38,10 @@
|
|
40
38
|
|
41
39
|
ところがジェネリクスを適用すると不変(異なる型)になります
|
42
40
|
ArrayList<Integer>とList<Number>は不変(invariant)
|
43
|
-
|
44
|
-
同様に以下の引数も不変です
|
45
41
|
Set<Number>とSet<Integer>は不変
|
46
42
|
|
47
43
|
従って、Javaの世界ではメソッドの引数の型が異なるのでオーバーロード
|
48
|
-
しかし、JVMの世界ではオーバーライド(ArrayListはListを実装するので共変型)
|
44
|
+
しかし、JVMの世界ではオーバーライド(ArrayListはListを実装するので共変型)
|
49
45
|
|
50
46
|
|
51
47
|
【自然な解決案(追記)】
|
1
Bのtestの戻り値がArrayList、【メソッドのオーバーライドについて(追記)】
test
CHANGED
@@ -7,14 +7,14 @@
|
|
7
7
|
Javaコンパイラはtestの引数の型Set<CharSequence>とSet<String>は別の型とみなします(不変)。testメソッドのシグネチャ(メソッド名と引数の型で決まる)はそれぞれ異なるので、メソッドがオーバーロードされています。
|
8
8
|
|
9
9
|
- Aのメソッド ... List<Number> test(Set<CharSequence>)
|
10
|
-
- Bのメソッド ... List<Integer> test(Set<String>)
|
10
|
+
- Bのメソッド ... ArrayList<Integer> test(Set<String>)
|
11
11
|
|
12
12
|
**JVMの世界**
|
13
13
|
|
14
14
|
バイトコードが生成される時、型イレージャによってジェネリクスの型が消され、要素の型はraw型(Object)になります。ただし、それぞれのメソッド内部で、必要なキャスト(checkcast)はコンパイラが補います。このようにtestメソッドがオーバーライドされたことになります。
|
15
15
|
|
16
16
|
- Aのメソッド ... List test(Set)
|
17
|
-
- Bのメソッド ... List test(Set)
|
17
|
+
- Bのメソッド ... ArrayList test(Set)
|
18
18
|
|
19
19
|
さて、これがコンパイルエラーにならず、仮にオーバーライドできたとすると、Aの型を持つ変数xにBのインスタンスを代入して x.test()を呼ぶとポリモーフィズムが働き、Bのtest()が呼ばれます。Aのtestの引数のSetにはStringBuilderを入れることができますが、Bのtest()は、処理の途中で、Setの要素をStringにキャストするのでエラーになります。
|
20
20
|
|
@@ -26,7 +26,57 @@
|
|
26
26
|
|
27
27
|
JavaとJVMの解釈に不整合が生じ実行時エラーがおきるため、コンパイルエラーにしているのだと思います。
|
28
28
|
|
29
|
+
【メソッドのオーバーライドについて(追記)】
|
30
|
+
|
31
|
+
メソッドのオーバーライドが質問の主題なので解説します。
|
32
|
+
|
33
|
+
メソッドがオーバーライド可能な条件
|
34
|
+
・メソッドのシグネチャが同一(メソッド名が同じ,メソッドの引数が同じ型で並びが同一)
|
35
|
+
・メソッドの戻り値の型が同一型か共変型(サブクラス、またはインターフェイスを実装するクラス)
|
36
|
+
・メソッドのアクセスレベルが同じか緩い
|
37
|
+
|
38
|
+
まずtestの戻り値が同一型か共変(variant)型かです。
|
39
|
+
ArrayListはListを実装するので共変型
|
40
|
+
|
41
|
+
ところがジェネリクスを適用すると不変(異なる型)になります
|
42
|
+
ArrayList<Integer>とList<Number>は不変(invariant)
|
43
|
+
|
44
|
+
同様に以下の引数も不変です
|
45
|
+
Set<Number>とSet<Integer>は不変
|
46
|
+
|
47
|
+
従って、Javaの世界ではメソッドの引数の型が異なるのでオーバーロード
|
48
|
+
しかし、JVMの世界ではオーバーライド(ArrayListはListを実装するので共変型)となります。
|
49
|
+
|
50
|
+
|
51
|
+
【自然な解決案(追記)】
|
52
|
+
|
53
|
+
Aで定義するNumber , CharSequenceは抽象クラスなので、Aも抽象クラスとするのが自然です。メソッドがオーバーロードと解釈されないようにクラスに型パラメータを定義します。以下のBのtest()は、A<String, Integer>の定義に従って、AのメソッドList<Integer> test(Set<String> s)をオーバーライドします。
|
54
|
+
|
55
|
+
```Java
|
56
|
+
// A
|
57
|
+
import java.util.List;
|
58
|
+
import java.util.Set;
|
59
|
+
|
60
|
+
public abstract class A<T extends CharSequence, U extends Number> {
|
61
|
+
public abstract List<U> test(Set<T> s);
|
62
|
+
}
|
63
|
+
|
64
|
+
// B
|
65
|
+
import java.util.ArrayList;
|
66
|
+
import java.util.Set;
|
67
|
+
import java.util.stream.Collectors;
|
68
|
+
|
69
|
+
public class B extends A<String, Integer> {
|
70
|
+
@Override
|
71
|
+
public ArrayList<Integer> test(Set<String> s) {
|
72
|
+
return s.stream().map(x -> Integer.valueOf(x)).collect(Collectors.toCollection(ArrayList::new));
|
73
|
+
}
|
74
|
+
}
|
75
|
+
```
|
76
|
+
|
77
|
+
### 以下は参考とします
|
78
|
+
|
29
|
-
**
|
79
|
+
**参考**
|
30
80
|
|
31
81
|
testメソッドの目的は、Set<T> -> List<U>に変換することです。本質はコレクションに関係なく、TをUに変換することですから、継承によって T -> U を解決します。
|
32
82
|
|