JAvaプログラミング思想読書ノート---第十四章タイプ情報

4108 ワード

ランタイムタイプ情報は、プログラムの実行時にタイプ情報を発見し、使用することができます.JAvaには、実行時にオブジェクトとクラスの情報を識別する2つの方法があります.1つは従来のRTTIであり、1つは「反射」メカニズムであり、実行時にクラスの情報を発見し、使用することができます.
1、なぜRTTIが必要なのか
  ベースクラスShapeが存在し、3つのサブクラスA、B、Cがあり、サブクラスをListに入れるとShapeにアップシフトしますが、実際にはlistにはObjectが保存されており、listから取り出すとShapeに変換され、その具体的なタイプが失われます.リストに保存されているのはShapeであり、これはコンパイル時に汎用的に強制的に確認される.実行時には、タイプ変換操作によって保証されます.次に,実際にどのようなコードを実行するかをマルチステートメカニズムによって決定する.通常、ほとんどのコードは、汎用タイプとのみ関連して、オブジェクトの特定のタイプをできるだけ少なく理解することが要求されます.このようなコードは書きやすく、読みやすく、メンテナンスしやすい.設計も実現しやすく理解しやすい.しかし、ある特殊なプログラミング問題に遭遇した場合、例えば、すべてのShapeを回転させるが、Bクラスをスキップする必要がある場合、この汎化参照の正確なタイプを知っていれば、簡単に解決することができる.正確なタイプはRTTIで取得できます.
2、Classオブジェクト
 javaはClassオブジェクトを使用してRTTIを実行します.各クラスにはクラスオブジェクトがあり、クラスを作成してコンパイルするたびに、クラスオブジェクト(.classファイルに含まれる)が生成されます.JVMはクラスローダを使用してこのクラスのオブジェクトを生成します.すべてのクラスは、最初の使用時にJVMに動的にロードされます.プログラムがクラスの静的メンバーへの最初の参照を作成すると、このクラスがロードされます.したがって,コンストラクタはstaticキーワードがなくてもクラスの静的メソッドである.したがってjavaプログラムは実行を開始するまで完全にロードされていません.クラスローダは、まずクラスのClassオブジェクトがロードするかどうかをチェックし、まだロードされていない場合は、デフォルトのクラスローダはクラス名に基づいて検索する.classファイル. getSimpleName()とgetCanonicalName()は、それぞれパッケージ名を含まないクラス名と、完全に限定されたクラス名を生成します.2.1類字面定数  Classを除く.forName()は、クラスの字面定数を使用してClassオブジェクトへの参照、すなわちA.classを生成することもできます.これにより、より簡単で、安全(コンパイル期間チェック)、効率的です.クラスフォント定数は、通常のクラスだけでなく、インタフェース、配列、および基本データ型にも適用できます.クラスを使用する前の準備作業には、次の3つのステップがあります.
  • がロードされ、クラスローダによって実行されます.このステップでは、バイトコードを検索し、これらのバイトコードからClassオブジェクトを作成します.
  • リンク.クラス内のバイトコードを検証し、静的ドメインのストレージスペースを作成し、必要に応じてクラスが作成した他のクラスへの参照を解析します.
  • 初期化.クラスにスーパークラスがある場合は、クラスを初期化します.  はforName()とは異なり、".class"を使用してClassオブジェクトへの参照を作成した場合、自動的にそのClassオブジェクトは初期化されません.初期化は、静的メソッドまたは非常数の静的ドメインへの最初の参照に遅延されてから実行される.  static final値が「コンパイル期間定数」である場合、この値はクラスを初期化する必要がなく読み込むことができます.ただし、ドメインをstaticおよびfinalに設定するだけでは、コンパイル期間定数ではない可能性があるため、この動作を確保するには十分ではありません.staticドメインがfinalでない場合、アクセス時には常に読み込み前に初期化とリンクが要求されます.2.2.汎化されたclassリファレンス  コンパイル期間のチェックを提供するために、Classリファレンスに汎型構文を追加した.newInstance()を使用すると、このタイプにはデフォルトのコンストラクション関数が必要で、Objectタイプが返されます.

  • 3、変換前にタイプチェックをする
      現在知られているRTTI形式:1)、従来のタイプ変換.「(Shape)」のように、誤った変換を実行すると例外が放出されます.2)、オブジェクトタイプを表すClassオブジェクト.3)キーワードinstanceof.従来のタイプ変換ではjavaがタイプチェック(タイプセキュリティのダウンシフト)を実行します.
    x instanceof A

     対象xがAクラスに属しているかどうかをチェックします.Instanceofの比較には厳格な制限があります.名前付きタイプと比較するだけで、Classオブジェクトと比較することはできません.コードにはinstanceofが多すぎるべきではありません.3.1.使用類字面定数3.2、動的instanceof class.isInstanceof()は、オブジェクトタイプを動的にテストする方法を提供します.
    4、工場の登録
      
    5、instanceofとClassの等価性
     instanceofとisInstance()の結果はまったく同じであり,==とequals()の結果も同じである.instanceofは、オブジェクトがこのクラスまたはこのクラスの派生クラスであるかどうかを比較するタイプの概念を維持しています.==Classオブジェクトを比較して、継承を考慮していません.それは、この正確なタイプであるか、そうではありません.
    6、反射:運転時のタイプ情報
    オブジェクトの正確なタイプが分からない場合は、RTTIが教えてくれます.しかし、もう1つの制限は、このタイプがコンパイルされると、RTTIを使用して認識できることです.すなわち、コンパイラは、コンパイル時に、RTTIによって処理されるすべてのクラスを知る必要があります.クラスとjava.lang.reflectクラスは、Field、Method、Constructクラス(クラスごとにMemberインタフェースが実装されている)を含む反射の概念をサポートしています.get()メソッドとset()メソッドでFieldオブジェクトに関連付けられたフィールドを読み取り、変更し、invoke()でMethodオブジェクトに関連付けられたメソッドを呼び出します.  RTTIの本当の違いは、RTTIにとってコンパイラがコンパイル時に開いてチェックすることにある.classファイル.反射機構としては、classファイルはコンパイル時に取得できないので、実行時に開いてチェックします.classファイル.
    7、動的エージェント
     javaの動的エージェントは、エージェントを動的に作成し、エージェントメソッドの呼び出しを動的に処理することができる.動的エージェントで行われたすべての呼び出しは、呼び出しのタイプを明らかにし、対応するポリシーを決定する単一の呼び出しプロセッサにリダイレクトされます.  静的メソッドを呼び出すことによってProxy.新ProxyInstance()は、動的エージェントを作成できます.このメソッドには、ロードされたオブジェクトからクラスローダを取得し、それに渡すことができるクラスローダ、エージェントが実装したいインタフェースのリスト(クラスまたは抽象クラスではない)、およびInvocationHandlerインタフェースの実装が必要です.動的エージェントは、すべての呼び出しを呼び出しプロセッサにリダイレクトすることができるため、通常、呼び出しプロセッサのコンストラクタに「実際の」オブジェクトの参照を伝え、呼び出しプロセッサが仲介タスクを実行するときに要求を転送できるようにします.
    8、空のオブジェクト
      
    9、インタフェースとタイプ情報
    interfaceキーワードの重要な目標は、プログラマがコンポーネントを分離し、結合性を低下させることである.しかし,タイプ情報により,この結合性は伝播する.  はインタフェースAがあると仮定し、BクラスはAの実装であり、Bのオブジェクトbを作成してAのオブジェクトaにアップコンバートすると、RTTIによってaがbによって実装されていることが判明し、aをBクラスに変換し、Aインタフェース内のBクラスを使用しない方法を呼び出すことができる.この問題は、パッケージ・アクセス権を使用して実装することによって解決できます.しかし,反射によりすべての実装クラスに到達して呼び出す方法(インタフェースに含まれない)は,内部クラスや匿名クラスを実装する方法では避けられない.一方、コードにこれらのアクセス権限が使用されている場合、使用者はそれらを呼び出すべきではないことを意味する.一方、常にクラスにバックドアを残しておくと、反射によるメリットは言うまでもありません.