java Type及項目實踐

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和List等類型,在編譯後都會變成List,JVM看到的只是List,而由泛型附加的類型信息對JVM是看不到的。Java編譯器會在編譯時儘可能的發現可能出錯的地方,但是仍然無法在運行時刻出現的類型轉換異常的情況.

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相關需求介紹

  1. 客戶端對網絡請求進行了封裝
  2. 網絡真實返回數據格式形如Result,而業務希望獲取的時Result裏面的data
Result<T> {
    T data;
    String code;
    String extra;
    String msg;
}
  1. 返回數據使用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
}
  1. 封裝層需要支持以上兩種數據的解析,並通過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,那麼當調用Class.getTypeParameters()方法得到的Type數組,數組的元素就是由TypeVariable接口實現的。 可以通過getTypeParameters判斷一個類是否爲泛型類。
真正的實現類是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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章