ClassオブジェクトからのRTTI(一)

7064 ワード


The normal goal in object-oriented programming is for your code to manipulate references to the base type.(オブジェクト向けプログラミングの基本目的は、コードがベースクラスへの参照のみを操作することである)--Thinking in javaから引用
       
もしある日、プログラミングがあなたにとってますます簡単になったことに気づいたら、あなたが書いたコードを振り返ってみると、あなたははっと悟ります.もともと多態はどこにもいませんでした.本の中でよく言われているように、ベースクラス(インタフェース)向けのプログラミングはコードを書きやすく、読みやすく、メンテナンスしやすくし、設計上も実現しやすく、理解し、変更しやすい.これはポイントではないと思います.重要なのは、これらの特性がますます彼を好きになることです.あなたがますますそれが好きになったとき、あなたが感じた楽しみはこれらの長所がもたらす快感をはるかに超えています.
       
本題に進んで,多態性をさらに理解するためには,まず動的バインディング(Dynamic Binding)と静的バインディング(Static Binding)を理解すべきである.
一、動的バインドと静的バインド
       
1、動的バインド
       
動的バインドとは、実行中に参照されるオブジェクトの実際のタイプを判断し、その実際のタイプに基づいてメソッドを呼び出すことです.動的バインディングは後期バインディングとも呼ばれ、動的バインディングはコンパイル中に呼び出されたメソッドを解析することができず、実行時にのみ正しく解析できることを理解できます.以下の例を示します.
class SuperClass {	
	public void doSomething(){
		System.out.println("SuperClass.doSomething");
	}
}
class SubClass extends SuperClass{
	public void doSomething(){
		System.out.println("SubClass.doSomething");
	}
}
public class Test {
	public static void main(String[] args){
		SuperClass sup = new SuperClass();
		SuperClass sub = new SubClass();
		sup.doSomething();
		sub.doSomething();
	}
}

       
Output:
SuperClass.doSomething
SubClass.doSomething

       
コンパイルフェーズではsupもsubもSuperの参照であり、実行時にはそれぞれSuperClassとSubClassを指していることがわかります.したがって、Javaでバインドを動的にバインドする方法は、宣言時のオブジェクトの参照タイプではなく、実際のオブジェクトタイプに基づいていることがわかります.(注:これらのメソッドは通常、書き換え可能な派生メソッドであるため、コンパイル期間中にメソッドのバージョンを識別することはできません)
       
2、静的バインド
       
コンパイラがコンパイル中に解析できるバインディングを静的バインディングまたは早期バインディング(Early Binding)と呼ぶ.すべてのインスタンスメソッド呼び出しは実行時に解析され、すべてのstaticメソッド呼び出しはコンパイル中に解析が完了します.静的な方法はclassの方法であり、オブジェクトの方法ではないため(もちろん、オブジェクトはこのような方法を呼び出すこともできる)、それらを解析するにはコンパイル期間だけでよい.△静的な方法は書き換えられますか.
       
同様に、Javaのメンバー変数も静的にバインドされます.Javaはメンバー変数のマルチステートを提供していません.以下の例を示します.
class SuperClass {	
	String variable = "the variable of SuperClass";
}
class SubClass extends SuperClass{
	String variable = "the variable of SubClass";
}
public class Test {
	public static void main(String[] args){
		SuperClass sup = new SuperClass();
		SuperClass sub = new SubClass();
		System.out.println(sup.variable);
		System.out.println(sub.variable);
	}
}

      
Output:
the variable of SuperClass
the variable of SuperClass

       
出力結果は同じで、実行時ではなくコンパイラでメンバー変数がバインドされていることを示します.これらの手がかりからprivate法もその派生法を実現できないため静的バインドであると推測できる.
       
3、リンク
       
動的バインドは多態に対するより深い認識をもたらし,もちろんその下層実装はまだ研究されていると言える.ここで多態といえば,多態はRTTIと相補的であるからである.だからどのようにそれらを理解して、RTTIは何で、どうしてRTTIを使うのか、などの問題はまだ解決しなければなりません.
二、マルチステートとRTTI
       
1、なぜRTTIが必要なのか
       
Thinking in Javaからの典型的な例です.
import java.util.List;
import java.util.Arrays;
public class Shapes {
	public static void main(String[] args){
		/**
		 *1、   Shape    List<Shape>         。      Shape       Shape       。
		 *2、       ,    Shape    ——             Object  。
		 *3、           ,             Shape,  RTTI        。
		 *4、 Shape          ,            Circle、Square Triangle    (  )。
		 */
		List<Shape> shapeList = Arrays.asList(new Circle(),new Square(),new Triangle());
		for(Shape shape : shapeList){
			shape.draw();
		}
	}
}
abstract class Shape{
	void draw(){System.out.println(this + ".draw()");}
	/**
	 *                 ,toString()         ,         String。
	 */
	abstract public String toString();
}

class Circle extends Shape{
	public String toString() {
		return "Circle";
	}
}
class Square extends Shape{
	public String toString() {
		return "Square";
	}
}
class Triangle extends Shape{
	public String toString() {
		return "Triangle";
	}
}

       
Output:
Circle.draw()
Square.draw()
Triangle.draw()

       
Javaでは、すべてのタイプ変換が実行時に正しくチェックされます.これもRTTI名の意味です.実行時にオブジェクトのタイプを識別します.
       
この例は、クラスコンパイラのタイプ変換を確保する汎用、RTTI、およびマルチステートを使用して、共通のタスクを完了します.RTTIは実行時のタイプ変換を完了した.マルチステートは、対応するオブジェクトに正しい動作を実行させます.
       
しかし、もし1つの対象ファミリーの汎用クラスが私たちのニーズを満たすことができない場合、私たちはどうすればいいのでしょうか.もし私たちが実行時に汎化参照の正確なタイプを識別することができれば、私たちは特別な問題に対する需要を満たすことができますが、この技術点はどのように解決すればいいのでしょうか.
       
2、リンク
       
RTTIは、上記の問題を解決し、実行時に汎化参照の正確なタイプをクエリーすることができます.RTTIの鍵を理解するには、Classオブジェクトから入手する必要があります!
三、Classオブジェクト
       
1、Classオブジェクトとは
       
クラスごとにClassオブジェクトがあります.Classオブジェクトには、クラスのすべての一般オブジェクトを作成するために使用されるクラスに関する情報が含まれています.
       
2、Classオブジェクトの由来
       
スタック領域にあるClassオブジェクトは、クラスロードの最終生成物であるクラスローダの動作目標です.
       
3、クラスのロード
       
クラスのロードとは、クラスの.classファイルのバイナリデータをメモリに読み込み、実行時のデータ領域のメソッド領域に配置し、クラスのメソッド領域内のデータ構造をカプセル化するためにスタック領域にjava.lang.classオブジェクトを作成することです.
       
1.すべてのクラスは、最初の使用時にJVMに動的にロードされます.プログラムがクラスに対する最初の静的メンバー参照を作成すると、このクラスがロードされます.
       
2、プログラムは実行を開始する前に完全にロードされていない.その部分は必要に応じてロードされる.(ダイナミックロード)
       
3、クラスローダはまずこのクラスのClassオブジェクトがロードされているかどうかをチェックします.まだロードされていない場合、デフォルトのクラス・ローダはクラス名に基づいて.classファイルを検索します.
       
4、クラスのクラスオブジェクトがメモリにロードされると、そのクラスのすべてのオブジェクトを作成するために使用されます.
       
次の例を示します.
class First{
	static { System.out.println("Loading First!"); }
}
class Second{
	static {System.out.println("Loading Second!");}
}
class Third{
	static {System.out.println("Loading Third!");}
}
public class LoadTest {
	//                   ,       
	public static void main(String[] args){
		System.out.println("start from main method");
		new First();
		new First();
		new First();
		System.out.println("After creating First");
		try{
			Class.forName("Second");
			new Second();
		}catch(ClassNotFoundException ep){
			System.out.println("Couldn't find Second");
		}
		System.out.println("After Creating Second");
		new Third();
		System.out.println("After creating Third");
	}
}

       
Output:
start from main method
Loading First!
After creating First
Loading Second!
After Creating Second
Loading Third!
After creating Third

       
4、リンク
       
クラスを使用する場合は、ロードするだけでは十分ではありません.使用するには、リンクと初期化も必要です.これらはただの始まりであり、実行時に汎化参照の具体的なタイプをどのように決定するか、Classオブジェクトをどのように安全に厳密に使用するかは、私たちが急いで解決しなければならない問題です.