java Type及項目實踐
一. 泛型基礎
泛型接口
public interface ITest<T> {
}
泛型方法
public <T> T testMethod(T param) {
return param;
}
匿名類
ITest t = new Itest<String> {
}
泛型邊界
// 下面定義的泛型爲帶邊界的泛型
public interface ITestWithUpper<T extend List> {
}
泛型擦除
Java的泛型基本上都是在編譯器這個層次上實現的,在生成的字節碼中是不包含泛型中的類型信息的,使用泛型的時候加上類型參數,在編譯器編譯的時候會去掉,這個過程成爲類型擦除。
如在代碼中定義List
public class Test {
public static void main(String[] args) throws Exception {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1); //這樣調用 add 方法只能存儲整形,因爲泛型類型的實例爲 Integer
list.getClass().getMethod("add", Object.class).invoke(list, "asd");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
// 其實運行可以發現,上述代碼“asd”是可以被添加到List中去的,說明List存儲的是原始對象(Object)
其實掌握以上基本上能cover住日常開發需求了。
二. type相關需求介紹
- 客戶端對網絡請求進行了封裝
- 網絡真實返回數據格式形如Result,而業務希望獲取的時Result裏面的data
Result<T> {
T data;
String code;
String extra;
String msg;
}
- 返回數據使用Gson解
data數據可能格式有兩種:
{"key1":"value1","key2":"value2"}
[{"key1":"value1_0","key2":"value2_0"},{"key1":"value1_1","key2":"value2_1"}]
假如RealResult
public RealResult {
@SerialName("key1")
String key1;
@SerialName("key2")
String key2
}
- 封裝層需要支持以上兩種數據的解析,並通過Gson一次完成數據解析
解決方案:
private Type getResponseType() {
if (mListResult) {
// 生成List<T> 中的 List<T>
Type listType = new ParameterizedTypeImpl(List.class, new Class[]{mResultClz});
// 根據List<T>生成完整的Result<List<T>>
return new ParameterizedTypeImpl(Result.class, new Type[]{listType});
} else {
return new ParameterizedTypeImpl(Result.class, new Class[]{mResultClz});
}
}
ParameterizedTypeImpl代碼如下:
public class ParameterizedTypeImpl implements ParameterizedType {
private final Class mRaw;
private final Type[] mArgs;
public ParameterizedTypeImpl(Class raw, Type[] args) {
this.mRaw = raw;
this.mArgs = args != null ? args : new Type[0];
}
@Override
public Type[] getActualTypeArguments() {
return mArgs;
}
@Override
public Type getRawType() {
return mRaw;
}
@Override
public Type getOwnerType() {
return null;
}
}
gson解析
Gson.fromJson(String xxxx, getResponseType()) 即可獲取到Result類型的數據,
再將Result裏面的data返回給業務。
三. Type
/**
*Type 是 Java 編程語言中所有類型的公共高級接口。它們包括原始類型、參數化類型、數組類型、類型變量和基本類型。
*從JDK1.5開始使用。
*/
public interface Type {
/**
* Returns a string describing this type, including information
* about any type parameters.
*
* @implSpec The default implementation calls {@code toString}.
*
* @return a string describing this type
* @since 1.8
* @hide Pending tests
*/
default String getTypeName() {
return toString();
}
}
原始類型:一般意義上的java類,由class類實現
參數化類型:ParameterizedType接口的實現類
數組類型:GenericArrayType接口的實現類
類型變量:TypeVariable接口的實現類
基本類型:int,float等java基本類型,其實也是class
網上貼出了一個例子:
public class TestReflect {
public static void test(TestReflect p0,
List<TestReflect> p1,
Map<String,TestReflect> p2,
List<String>[] p3,
Map<String,TestReflect>[] p4,
List<? extends TestReflect> p5,
Map<? extends TestReflect,? super TestReflect> p6){
}
以下代碼獲取七個參數的type
Method[] methods=TestReflect.class.getMethods();
Type[] types=oneMethod.getGenericParameterTypes(); // 獲取p0-p6 7個參數的type
Class(原始類型/raw types)
普通的java類(比如String,Integer,Method等等),
數組,
自定義類(比如我們自己定義的TestReflect類),
8種java基本類型(比如int,float等)
可能還有其他的類
Class type0=(Class)types[0];
System.out.println("type0:"+type0.getName());
// 輸出結果爲: type0:com.selftest.test.testapp3.java_type.Types.TestReflect
ParameterizedType
當需要描述的類是泛型類時,比如List,Map等,不論代碼裏寫沒寫具體的泛型,java會選擇ParameterizedType接口做爲Type的實現。
真正的實現類是sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl。
ParameterizedType接口有getActualTypeArguments()方法,用於得到泛型的Type類型數組。
//第二個參數,List< TestReflect > p1
Type type1=types[1];
Type[] parameterizedType1=((ParameterizedType)type1).getActualTypeArguments();
Class parameterizedType1_0=(Class)parameterizedType1[0]; // 如果有多個泛型都可以獲取,如p2
System.out.println(parameterizedType1_0.getName());
//輸出結果爲: parameterizedType1_0:com.selftest.test.testapp3.java_type.Types.TestReflect
上述可以獲取List中泛型的Type, 針對上面網絡請求封裝需求時使用的就是實現ParameterizedType,將泛型傳給GSON,從而能直接從GSON中直接parse出泛型對象。
GenericArrayType
當需要描述的類型是泛型類的數組時,比如比如List[],Map[],type會用GenericArrayType接口作爲Type的實現。
真正的實現類是sun.reflect.generics.reflectiveObjects. GenericArrayTypeImpl。
GenericArrayType接口有getGenericComponentType()方法,得到數組的組件類型的Type對象。
//第四個參數,List<String>[] p3
Type type3=types[3];
Type genericArrayType3=((GenericArrayType)type3).getGenericComponentType();
ParameterizedType parameterizedType3=(ParameterizedType)genericArrayType3;
Type[] parameterizedType3Arr=parameterizedType3.getActualTypeArguments();
Class class3=(Class)parameterizedType3Arr[0];
System.out.println("class3:"+class3.getName());
輸出: class3:java.lang.String
WildcardType
當需要描述的類型是泛型類,而且泛型類中的泛型被定義爲(? extends xxx)或者(? super xxx)這種類型,比如List<? extends TestReflect>,這個類型首先將由ParameterizedType實現,當調用ParameterizedType的getActualTypeArguments()方法後得到的Type就由WildcardType實現。
真正的實現類是sun.reflect.generics.reflectiveObjects. WildcardTypeImpl。
WildcardType接口有getUpperBounds()方法,得到的是類型的上邊界的Type數組,實際上就是類型的直接父類,也就是extends後面的類型。顯然在當前java的設定中,這個數組只可能有一個元素,因爲java現在只能extends一個類。如果實在沒寫extends,那他的直接父類就是Object。
WildcardType接口有getLowerBounds()方法,得到的是類型的下邊界的Type數組,有super關鍵字時可能會用到,經測試不會得到類型的子類,而是只得到super關鍵字後面的類型,如果沒寫super關鍵字,則返回空數組。
//第六個參數,List<? extends TestReflect> p5
Type type5=types[5];
Type[] parameterizedType5=((ParameterizedType)type5).getActualTypeArguments();
Type[] parameterizedType5_0_upper=((WildcardType)parameterizedType5[0]).getUpperBounds();
Type[] parameterizedType5_0_lower=((WildcardType)parameterizedType5[0]).getLowerBounds();
System.out.println("upper=" + parameterizedType5_0_upper[0]);
System.out.println("lower=" + parameterizedType5_0_lower.length);
// 輸出:
// upper=class com.selftest.test.testapp3.java_type.Types.TestReflect
// lower=0
TypeVariable
Type的最後一種實現形式是TypeVariable接口,這種實現形式是在泛型類中使用的。
比如我們定義一個泛型類TestReflect
真正的實現類是sun.reflect.generics.reflectiveObjects. TypeVariableImpl。
public class TypeTestClass<RESULT> {}
TypeVariable[] types = TypeTestClass.class.getTypeParameters();
System.out.println("type=" + types[0].getName());
//輸出爲:type=RESULT, 只能獲取顯示的泛型名,不能獲取到真正的類型
https://www.jianshu.com/p/a8e883aa3351