回答編集履歴

3

用語の誤りを訂正

2023/01/23 10:35

投稿

xebme
xebme

スコア1081

test CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  **Javaの世界**
6
6
 
7
- Javaコンパイラはtestの引数の型Set<CharSequence>とSet<String>は別の型とみなします(変)。testメソッドのシグネチャ(メソッド名と引数の型で決まる)はそれぞれ異なるので、メソッドがオーバーロードされています。
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>は変(invariant)
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

 冗長な部分を簡潔に

2023/01/22 23:11

投稿

xebme
xebme

スコア1081

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、【メソッドのオーバーライドについて(追記)】

2023/01/22 22:56

投稿

xebme
xebme

スコア1081

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