ホームページ  >  記事  >  Java  >  JavaでTypeTokenを使用する方法

JavaでTypeTokenを使用する方法

王林
王林転載
2023-05-16 08:49:051677ブラウズ

ジェネリックの消去

ご存知のとおり、Java のジェネリックはコンパイル時にのみ有効であり、ジェネリック型、つまり List< ;String> は実行時に消去されます。 ; と List は、実行時には実際には List 型になります。

この実装メカニズムを選択する理由は何ですか?そのまま消すことはできないのでしょうか?私が C テンプレートに似た概念、つまりジェネリックを実装したいと思ったのは、Java の誕生から 10 年後でした。 Java のクラス ライブラリは、Java エコシステムにおいて非常に貴重な資産であり、下位互換性 (つまり、既存のコードとクラス ファイルは依然として合法である) と移行互換性 (一般化されたコードと非一般化されたコードが相互に呼び出せる) を保証する必要があります。上記 2 つの背景と考慮事項により、Java 設計者は「型消去」という妥協的な実装方法を採用しました。

同時に、実行時に特定の種類のジェネリック パラメーターを自由に取得できないようにする「ホール」メカニズムもあります。

TypeToken

Use

Gson を使用したことのある学生は、逆シリアル化中に TypeToken 型を定義する必要があることを知っています。 this

private Type type = new TypeToken<List<Map<String, Foo>>>(){}.getType();  //调用fromJson方法时把type传过去,如果type的类型和json保持一致,则可以反序列化出来  gson.fromJson(json, type);

3 つの質問

1. 逆シリアル化された型を定義するのに TypeToken を使用するのはなぜですか?上で述べたように、List> の型を直接渡しても、ランタイム ジェネリックスが消去されているため、実際に取得されるのは List である場合、後続の Gson はそれが必要であることを認識しません。 Map タイプに変換されると、Gson はデフォルトで LinkedTreeMap タイプに変換します。

2.中括弧 {} があるのはなぜですか?このブレースが本質です。ご存知のとおり、Java 構文では、このコンテキストで {} を使用して匿名クラスを定義します。この匿名クラスは、TypeToken のサブクラスである TypeToken クラスを継承します。

3. サブクラスを通じてジェネリック型を取得する必要があるのはなぜですか?これは、TypeToken がジェネリック型を取得できるようにするための鍵であり、賢い方法です。アイデアは次のようになります。List のジェネリックスが消去されるため、サブクラス SubList extends List を使用します。この場合、親クラスは JVM 内でジェネリック化されますか? どのような型が保存されますか? ?

サブクラスが継承する必要がある親クラスのジェネリックスが決定されました。案の定、JVM はこの部分の情報を保存し、サブクラスのクラス情報に保存されます。

では、この情報はどうやって入手するのでしょうか?幸いなことに、Java には API が用意されています:

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

要約すると、ジェネリックを持つクラスの場合は ParameterizedType オブジェクトが返され、Object、インターフェイス、およびプリミティブ型の場合は null が返され、配列クラスの場合は Object が返されます。クラス。 ParameterizedType は、ジェネリック パラメータを持つ型を表す Java タイプです。JDK1.5 でのジェネリックの導入後、Java のすべてのクラスは Type インターフェイスを実装します。ParameterizedType は Type インターフェイスを継承します。ジェネリックを含むすべてのクラス クラスは、このインターフェイスを実装します。

自分でデバッグすれば、何が返されるかがわかります。

原則

核となるメソッドは先ほど述べた 2 つの文で、残りは非常に簡単です。 TypeToken の getType メソッドを見てみましょう

public final Type getType() {   //直接返回type      return type;    }

type の初期化を見てみましょう

//注意这里用了protected关键字,限制了只有子类才能访问  protected TypeToken() {      this.type = getSuperclassTypeParameter(getClass());      this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);      this.hashCode = type.hashCode();    }      //getSuperclassTypeParameter方法    //这几句就是上面的说到    static Type getSuperclassTypeParameter(Class<?> subclass) {      Type superclass = subclass.getGenericSuperclass();      if (superclass instanceof Class) {        throw new RuntimeException("Missing type parameter.");      }      ParameterizedType parameterized = (ParameterizedType) superclass;      //这里注意一下,返回的是Gson自定义的,在$Gson$Types里面定义的TypeImpl等,这个类都是继承Type的。      return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);    }

以上がJavaでTypeTokenを使用する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。