TypeToken 是google提供的一個解析Json數據的類庫中一個類


Type listType = new TypeToken<LinkedList<User>>(){}.getType();
Type是java里的reflect包的Type ,TypeToken 是google提供的一個解析Json數據的類庫中一個類
問題1:如果我沒有寫大括號{};就是TypeToken<LinkedList<User>>()后面的這個{},eclipse會報出 構造函數不可見,加上就好了,可是我在自己創建的2個測試類里
這樣做就不行,如果構造是private的,加不加大括號都不行這是為什么

問題2:通常情況下,不加大括號是什么情況?加上又是什么情況,他們的含義是什么,作用是什么,

 

 

不加大括號表示很普通的new一個對象。。如果那個類的構造方法是私有的。。肯定不能直接new了。。就會編譯報錯。。
加上大括號表示你new了一個匿名內部類的對象。。比如new TypeToken<LinkedList<User>>(){}。。表示你new的是一個匿名內部類的對象。。這個匿名類繼承自TypeToken類。。你可以在大括號里面像寫其他普通類代碼一樣隨意寫代碼。。你可以在里面定義個方法等等。。

主要你不能理解的原因我想是你不了解內部類。。多看內部類的知識就會明白了。。new TypeToken<LinkedList<User>>(){}匿名內部類常用在監聽里面。。比如我們給一個按鈕加監聽。。比如
JButton btn = new JButton("test");
        btn.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				
			}
		});
 btn.addActionListener()方法接受的是一個ActionListener類型的對象。。而ActionListener是一個接口。。不能直接new。。所以本來我們應該寫一個類實現ActionListener接口。。然后這里給他傳一個那個實現類的對象。。但是。。我們不想那么麻煩了。。因為這種情況太多。。所以我們直接在這里創建了那個類。。之所以叫匿名。。就是我們沒有給他取名字就讓他叫ActionListener接口的名字。。然后在這里實現那個方法。。


最近在使用Google的Gson包進行Json和Java對象之間的轉化,對於包含泛型的類的序列化和反序列化Gson也提供了很好的支持,感覺有點意思,就花時間研究了一下。

由於Java泛型的實現機制,使用了泛型的代碼在運行期間相關的泛型參數的類型會被擦除,我們無法在運行期間獲知泛型參數的具體類型(所有的泛型類型在運行時都是Object類型)。

但是有的時候,我們確實需要獲知泛型參數的類型,比如將使用了泛型的Java代碼序列化或者反序列化的時候,這個時候問題就變得比較棘手。

復制代碼
class Foo<T> {
  T value;
}
Gson gson = new Gson();
Foo<Bar> foo = new Foo<Bar>();
gson.toJson(foo); // May not serialize foo.value correctly
 
gson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar
復制代碼

對於上面的類Foo<T>,由於在運行期間無法得知T的具體類型,對這個類的對象進行序列化和反序列化都不能正常進行。Gson通過借助TypeToken類來解決這個問題。

復制代碼
TestGeneric<String> t = new TestGeneric<String>();
  t.setValue("Alo");
  Type type = new TypeToken<TestGeneric<String>>(){}.getType();
   
  String gStr = GsonUtils.gson.toJson(t,type);
  System.out.println(gStr);
  TestGeneric t1 = GsonUtils.gson.fromJson(gStr, type);
  System.out.println(t1.getValue());
復制代碼

TypeToken的使用非常簡單,如上面的代碼,只要將需要獲取類型的泛型類作為TypeToken的泛型參數構造一個匿名的子類,就可以通過getType()方法獲取到我們使用的泛型類的泛型參數類型。

下面來簡單分析一下原理。

要獲取泛型參數的類型,一般的做法是在使用了泛型的類的構造函數中顯示地傳入泛型類的Class類型作為這個泛型類的私有屬性,它保存了泛型類的類型信息。

復制代碼
public class Foo<T>{
  
 public Class<T> kind;
  
 public Foo(Class<T> clazz){
  this.kind = clazz;
 }
  
 public T[] getInstance(){
  return (T[])Array.newInstance(kind, 5);
 }
  
 public static void main(String[] args){
  Foo<String> foo = new Foo(String.class);
  String[] strArray = foo.getInstance();
 }
 
}
復制代碼

這種方法雖然能解決問題,但是每次都要傳入一個Class類參數,顯得比較麻煩。Gson庫里面對於這個問題采用了了另一種解決辦法。

同樣是為了獲取Class的類型,可以通過另一種方式實現:

復制代碼
public abstract class Foo<T>{
  
 Class<T> type;
  
 public Foo(){
  this.type = (Class<T>) getClass();
 }
 
        public static void main(String[] args) {
   
  Foo<String> foo = new Foo<String>(){};
  Class mySuperClass = foo.getClass();
 
 }
  
}
復制代碼

聲明一個抽象的父類Foo,匿名子類將泛型類作為Foo的泛型參數傳入構造一個實例,再調用getClass方法獲得這個子類的Class類型。

這里雖然通過另一種方式獲得了匿名子類的Class類型,但是並沒有直接將泛型參數T的Class類型傳進來,那又是如何獲得泛型參數的類型的呢, 這要依賴Java的Class字節碼中存儲的泛型參數信息。Java的泛型機制雖然在運行期間泛型類和非泛型類都相同,但是在編譯java源代碼成 class文件中還是保存了泛型相關的信息,這些信息被保存在class字節碼常量池中,使用了泛型的代碼處會生成一個signature簽名字段,通過 簽名signature字段指明這個常量池的地址。

關於class文件中存儲泛型參數類型的具體的詳細的知識可以參考這里:http://stackoverflow.com/questions/937933/where-are-generic-types-stored-in-java-class-files

JDK里面提供了方法去讀取這些泛型信息的方法,再借助反射,就可以獲得泛型參數的具體類型。同樣是對於第一段代碼中的foo對象,通過下面的代碼可以得到foo<T>中的T的類型:

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

運行結果是class java.lang.String。

分析一下這段代碼,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,對於數 組class則是返回Object.class。ParameterizedType是表示帶有泛型參數的類型的Java類型,JDK1.5引入了泛型之 后,Java中所有的Class都實現了Type接口,ParameterizedType則是繼承了Type接口,所有包含泛型的Class類都會實現 這個接口。

實際運用中還要考慮比較多的情況,比如獲得泛型參數的個數避免數組越界等,具體可以參看Gson中的TypeToken類及ParameterizedTypeImpl類的代碼。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM