自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

掌握Java-TypeToken原理及泛型擦除

開發(fā) 后端
借助對TypeToken原理的分析,加強對泛型擦除的理解,使得我們能夠知道什么時候,通過什么方式可以獲取到泛型的類型。

 [[359081]]

概要

借助對TypeToken原理的分析,加強對泛型擦除的理解,使得我們能夠知道什么時候,通過什么方式可以獲取到泛型的類型。

泛型擦除

眾所周知,Java的泛型只在編譯時有效,到了運行時這個泛型類型就會被擦除掉,即List<String>和List<Integer>在運行時其實都是List<Object>類型。

為什么選擇這種實現(xiàn)機制?不擦除不行么?在Java誕生10年后,才想實現(xiàn)類似于C++模板的概念,即泛型。Java的類庫是Java生態(tài)中非常寶貴的財富,必須保證向后兼容(即現(xiàn)有的代碼和類文件依舊合法)和遷移兼容(泛化的代碼和非泛化的代碼可互相調(diào)用)基于上面這兩個背景和考慮,Java設計者采取了“類型擦除”這種折中的實現(xiàn)方式。

同時正正有這個這么“坑”的機制,令到我們無法在運行期間隨心所欲的獲取到泛型參數(shù)的具體類型。

TypeToken

使用

使用過Gson的同學都知道在反序列化時需要定義一個TypeToken類型,像這樣 

  1. private Type type = new TypeToken<List<Map<String, Foo>>>(){}.getType();  
  2. //調(diào)用fromJson方法時把type傳過去,如果type的類型和json保持一致,則可以反序列化出來  
  3. gson.fromJson(json, type); 

三個問題

1.為什么要用TypeToken來定義反序列化的類型?正如上面說的,如果直接把List<Map<String, Foo>>的類型傳過去,但是因為運行時泛型被擦除了,所以得到的其實是List<Object>,那么后面的Gson就不知道要轉(zhuǎn)成Map<String, Foo>類型了,這時Gson會默認轉(zhuǎn)成LinkedTreeMap類型。

2.為什么帶有大括號{}?這個大括號就是精髓所在。大家都知道,在Java語法中,在這個語境,{}是用來定義匿名類,這個匿名類是繼承了TypeToken類,它是TypeToken的子類。

3.為什么要通過子類來獲取泛型的類型?這是TypeToken能夠獲取到泛型類型的關鍵,這是一個巧妙的方法。這個想法是這樣子的,既然像List<String>這樣中的泛型會被擦除掉,那么我用一個子類SubList extends List<String>這樣的話,在JVM內(nèi)部中會不會把父類泛型的類型給保存下來呢?

我這個子類需要繼承的父類的泛型都是已經(jīng)確定了的呀,果然,JVM是有保存這部分信息的,它是保存在子類的Class信息中。

具體看:

https://stackoverflow.com/questions/937933/where-are-generic-types-stored-in-java-class-files

那么我們怎么獲取這部分信息呢?還好,Java有提供API出來: 

  1. Type mySuperClass = foo.getClass().getGenericSuperclass();  
  2. Type type = ((ParameterizedType)mySuperClass).getActualTypeArguments()[0];  
  3. System.out.println(type); 

分析一下這段代碼,Class類的getGenericSuperClass()方法的注釋是:

Returns the Type representing the direct superclass of the entity (class, interface, primitive type or void) represented by thisClass. If the superclass is a parameterized type, the Type object returned must accurately reflect the actual type parameters used in the source code. The parameterized type representing the superclass is created if it had not been created before. See the declaration of ParameterizedType for the semantics of the creation process for parameterized types. If thisClass represents either theObject class, an interface, a primitive type, or void, then null is returned. If this object represents an array class then theClass object representing theObject class is returned

概括來說就是對于帶有泛型的class,返回一個ParameterizedType對象,對于Object、接口和原始類型返回null,對于數(shù) 組class則是返回Object.class。ParameterizedType是表示帶有泛型參數(shù)的類型的Java類型,JDK1.5引入了泛型之 后,Java中所有的Class都實現(xiàn)了Type接口,ParameterizedType則是繼承了Type接口,所有包含泛型的Class類都會實現(xiàn) 這個接口。

自己調(diào)試一下就知道它返回的是什么了。

原理

核心的方法就是剛剛說的那兩句,剩下的就很簡單了。我們看看TypeToken的getType方法 

  1. public final Type getType() {  
  2.  //直接返回type  
  3.     return type;  
  4.   } 

看type的初始化 

  1. //注意這里用了protected關鍵字,限制了只有子類才能訪問  
  2. protected TypeToken() {  
  3.     this.type = getSuperclassTypeParameter(getClass());  
  4.     this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);  
  5.     this.hashCode = type.hashCode();  
  6.   }    
  7.   //getSuperclassTypeParameter方法  
  8.   //這幾句就是上面的說到  
  9.   static Type getSuperclassTypeParameter(Class<?> subclass) {  
  10.     Type superclass = subclass.getGenericSuperclass();  
  11.     if (superclass instanceof Class) {  
  12.       throw new RuntimeException("Missing type parameter.");  
  13.     }  
  14.     ParameterizedType parameterized = (ParameterizedType) superclass;  
  15.     //這里注意一下,返回的是Gson自定義的,在$Gson$Types里面定義的TypeImpl等,這個類都是繼承Type的。  
  16.     return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);  
  17.   } 

總結(jié)

在了解原理之后,相信大家都知道怎么去獲取泛型的類型了。 

 

責任編輯:龐桂玉 來源: Java知音
相關推薦

2021-07-01 06:47:30

Java泛型泛型擦除

2021-07-29 09:20:18

Java泛型String

2021-09-29 18:17:30

Go泛型語言

2023-03-06 08:33:24

IDEA反編譯類型

2019-09-04 00:20:10

JSON泛型擦除

2024-06-07 10:05:31

2017-03-06 16:51:52

Java泛型實現(xiàn)

2025-01-13 07:00:00

Java泛型編程

2021-08-24 08:05:41

泛型類型擦除Class

2024-01-15 08:28:31

Spring事件

2022-03-02 14:41:03

泛型反序列化

2009-09-25 10:03:51

Java泛型

2009-08-24 11:35:20

C# 泛型應用

2009-08-24 10:37:27

C# 泛型

2009-12-24 09:16:11

C#泛型

2022-06-14 09:01:06

TypeScript泛型

2021-12-30 19:34:15

Java泛型JDK

2023-11-20 13:51:00

泛型函數(shù)TypeScript

2011-06-03 08:49:54

Java

2021-06-17 06:51:32

Java泛型Java編程
點贊
收藏

51CTO技術棧公眾號