Java静的汎用メソッド
JavaはJDK 5に汎用型を導入し、使いやすくなりました.以下は一般的な汎用型の使用です.
汎用メソッドの使用
コレクションで使用できるだけでなく、クラス、インタフェース、メソッドを定義する際にもよく使用されますが、汎用メソッドで使用されるシーンはあまり多くありません.次に、2つの数の最大数を求める実装から、汎用クラスと汎用メソッドの簡単な使用を見てみましょう.
汎用クラス(インタフェース)
汎用メソッド
静的汎用メソッド
汎用メソッドの長所と短所
利点は明らかで、コードが簡潔になったこと、あるいは普通の汎用型よりも簡潔と言える.ネット上にはAndroidで頻繁に使われている一節がある.
上記のコードは コンパイルが通過し、異常が実行されるのは、なぜこのような現象が発生するのでしょうか.これはJavaの汎用メソッドが擬似汎用に属し,コンパイル時にタイプ消去が行われるためである.通常の汎用メソッドではクラス構築時に対応するタイプが明確に定められているが,静的汎用メソッドではタイプが直接推測できず,明確なタイプが欠け,最終的にタイプ転化異常をもたらす.
原理の探求
以上の結果を見て、汎用メソッドがタイプ消去後に最終的に何に変換されたのかを知りたくなりました.上記の静的汎用メソッドを逆コンパイルしてコンパイルしたclassファイルは以下の通りです.
convert関数の最終変換後の対応するバイトコードは
上記のコードに対して逆コンパイル後対応
小結
Javaの汎用は擬似汎用ですが、汎用はコードをより簡潔にすることができ、使用しているだけです.
もっと多くの文章は小太り軒を訪問してください.
List list = new ArrayList();
汎用メソッドの使用
コレクションで使用できるだけでなく、クラス、インタフェース、メソッドを定義する際にもよく使用されますが、汎用メソッドで使用されるシーンはあまり多くありません.次に、2つの数の最大数を求める実装から、汎用クラスと汎用メソッドの簡単な使用を見てみましょう.
汎用クラス(インタフェース)
package me.codeboy.test;
/**
* generic test
* Created by yuedong on 9/12/16.
*/
public class MathTest {
public static void main(String[] args) {
MathTest mathTest1 = new MathTest();
MathTest mathTest2 = new MathTest();
System.out.println(mathTest1.max(1, 2));
System.out.println(mathTest2.max(2.0, 3.0));
}
private T max(T t1, T t2) {
return t1.compareTo(t2) > 0 ? t1 : t2;
}
}
汎用メソッド
/**
* generic test
* Created by yuedong on 9/12/16.
*/
public class MathTest {
public static void main(String[] args) {
MathTest mathTest = new MathTest();
System.out.println(mathTest.max(1, 2));
System.out.println(mathTest.max(2.0, 3.0));
}
private T max(T t1, T t2) {
return t1.compareTo(t2) > 0 ? t1 : t2;
}
}
静的汎用メソッド
/**
* generic test
* Created by yuedong on 9/12/16.
*/
public class MathTest {
public static void main(String[] args) {
System.out.println(max(1, 2));
System.out.println(max(2.0, 3.0));
}
private static T max(T t1, T t2) {
return t1.compareTo(t2) > 0 ? t1 : t2;
}
}
汎用メソッドの長所と短所
利点は明らかで、コードが簡潔になったこと、あるいは普通の汎用型よりも簡潔と言える.ネット上にはAndroidで頻繁に使われている一節がある.
findViewById
メソッドの静的汎用メソッド実装は、最も強力なAndroidコードを見たことがあると言われていますが、物事には両面性があり、静的汎用メソッドにも欠点があります.コードを見てみましょう.import java.util.ArrayList;
import java.util.List;
/**
* test entry
* Created by yuedong on 9/10/16.
*/
public class Test {
public static void main(String[] args) {
List list = new ArrayList<>();
list.add("test");
//
ArrayList result1 = (ArrayList) list;
//
String result2 = convert(list);
}
private static T convert(Object a) {
return (T) a;
}
}
上記のコードは コンパイルが通過し、異常が実行されるのは、なぜこのような現象が発生するのでしょうか.これはJavaの汎用メソッドが擬似汎用に属し,コンパイル時にタイプ消去が行われるためである.通常の汎用メソッドではクラス構築時に対応するタイプが明確に定められているが,静的汎用メソッドではタイプが直接推測できず,明確なタイプが欠け,最終的にタイプ転化異常をもたらす.
Exception in thread "main" java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.String
原理の探求
以上の結果を見て、汎用メソッドがタイプ消去後に最終的に何に変換されたのかを知りたくなりました.上記の静的汎用メソッドを逆コンパイルしてコンパイルしたclassファイルは以下の通りです.
Compiled from "Test.java"
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2 // class java/util/ArrayList
3: dup
4: invokespecial #3 // Method java/util/ArrayList."":()V
7: astore_1
8: aload_1
9: ldc #4 // String test
11: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
16: pop
17: aload_1
18: checkcast #2 // class java/util/ArrayList
21: astore_2
22: aload_1
23: invokestatic #6 // Method convert:(Ljava/lang/Object;)Ljava/lang/Object;
26: checkcast #7 // class java/lang/String
29: astore_3
30: return
}
convert関数の最終変換後の対応するバイトコードは
Method convert:(Ljava/lang/Object;)Ljava/lang/Object;
パラメータはObjectタイプで、戻りもObjectタイプで、次の checkcast
操作中、 List
および String
タイプが違うので、異常を投げ出しました. private static T convert(Object a) {
return (T) a;
}
上記のコードに対して逆コンパイル後対応
Method convert:(Ljava/lang/Object;)Ljava/util/List;
で、このときパラメータがObjectタイプであり、Listタイプとして返されることがわかります.小結
Javaの汎用は擬似汎用ですが、汎用はコードをより簡潔にすることができ、使用しているだけです.
および
タイプ変換に特に注意する必要があります.もっと多くの文章は小太り軒を訪問してください.