JavaにおけるClassクラスの動作原理の詳細

15810 ワード

1.Classオブジェクト
Classオブジェクトには、クラスに関する情報が含まれています.実際、クラスオブジェクトはクラスのすべての「通常」オブジェクトを作成するために使用されます.
クラスはプログラムの一部であり、各クラスにはClassオブジェクトがあります.すなわち、新しいクラスを作成してコンパイルするたびに、Classオブジェクトが生成される(適切には、同じ名前の.classファイルに保存される).実行時に、このクラスのオブジェクトを生成したい場合、このプログラムを実行するJava仮想マシン(JVM)は、まずこのクラスのClassオブジェクトがロードされているかどうかを確認します.まだロードされていない場合、JVMはクラス名に基づいて検索されます.classファイルをロードします.
クラスのクラスオブジェクトがメモリにロードされると、そのクラスのすべてのオブジェクトを作成するために使用されます.次の例を見てください.
SweetShop.java
package com.zj.sample;
 
class Candy {
    static {
       System.out.println("Loading Candy");
    }
}
 
class Gum {
    static {
       System.out.println("Loading Gum");
    }
}
 
class Cookie {
    static {
       System.out.println("Loading Cookie");
    }
}
 
public class SweetShop {
    public static void main(String[] args) {
       System.out.println("inside main");
       new Candy();
       System.out.println("After creating Candy");
       try {
           Class.forName("com.zj.sample.Gum");
       } catch (ClassNotFoundException e) {
           System.out.println("Couldn't find Gum");
       }
       System.out.println("After Class.forName(/"Gum/")");
       new Cookie();
       System.out.println("After creating Cookie");
    }
}

結果:
inside main
Loading Candy
After creating Candy
Loading Gum
After Class.forName("Gum")
Loading Cookie
After creating Cookie
2.Classインスタンスを取得する3つの方法
1)オブジェクト呼び出しgetClass()メソッドでそのオブジェクトのClassインスタンスを取得する.
2)Classクラスの静的メソッドforName()を使用してクラス名でClassインスタンスを取得します.
3)运用Class方式でClassインスタンスを取得する、基本データ型のカプセル化クラスについても用いることができる.TYPEは、対応する基本データ型のClassインスタンスを取得する.
3.Class.forName
上記の例では、
Class.forName("com.zj.sample.Gum");
このメソッドは、クラス(すべてのクラスオブジェクトがこのクラスに属している)のstaticメンバーです.Classオブジェクトは、他のオブジェクトと同様に参照を取得して操作できます.forName()はClassオブジェクトの参照を取得する方法です.ターゲットクラスのテキスト名を含むStringを入力パラメータとして使用し、Classオブジェクトの参照を返します.
4.類字面定数
Javaはまた、Classオブジェクトへの参照を生成するための別の方法を提供します.すなわち、「クラス文字定数」を使用します.上記の手順では、次のことができます.
com.zj.sample.Gum.class;
5.キーワードinstanceof
キーワードinstanceofは、特定のタイプのインスタンスかどうかを判断するブール値を返します.
if(x instanceof Dog) {
((Dog)x).bark();
}
JAvaのinstanceof演算子は、実行時にオブジェクトが特定のクラスであるかどうかを示すインスタンスです.
instanceofは、このオブジェクトがこの特定のクラスまたはそのサブクラスのインスタンスであるかどうかを示すブール値を返します.使用法:result=object instanceof classパラメータ:Result:ブールタイプ.Object:必須オプション.任意のオブジェクト式.Class:必須です.定義されたオブジェクトクラス.説明:objectがclassのインスタンスである場合、instanceof演算子はtrueを返します.objectが指定したクラスのインスタンスでない場合、またはobjectがnullの場合、falseが返されます.
6.Classインスタンスの取得
package com.zj.sample;
 
class Point {
    int x, y;
}
 
class ClassTest {
    public static void main(String[] args) {
       Point pt = new Point();
       Class c1 = pt.getClass();
       System.out.println(c1.getName());
 
       try {
           Class c2 = Class.forName("com.zj.sample.Point");
           System.out.println(c2.getName());
       } catch (Exception e) {
           e.printStackTrace();
       }
 
       Class c3 = Point.class;
       System.out.println(c3.getName());
 
       Class c4 = int.class;
       System.out.println(c4.getName());
 
       Class c5 = Integer.TYPE;
       System.out.println(c5.getName());
 
       Class c6 = Integer.class;
       System.out.println(c6.getName());
    }
}

結果:
com.zj.sample.Point
com.zj.sample.Point
com.zj.sample.Point
int
int
java.lang.Integer
getName
public String getName()

このClassオブジェクトが表すエンティティ(クラス、インタフェース、配列クラス、基本タイプ、void)の名前をStringとして返します.
このようなオブジェクトが非配列タイプの参照タイプを表す場合、クラスのバイナリ名が返され、Java Language Specification、Second Editionが詳細に説明します.
このようなオブジェクトが基本タイプまたはvoidを表す場合、返される名前は、その基本タイプまたはvoidに対応するJava言語キーワードと同じStringです.
このようなオブジェクトが配列クラスを表す場合、名前の内部形式は、配列のネストの深さを表す1つ以上の'['文字に要素タイプ名を付けます.要素タイプ名の符号化は次のとおりです.
Element Type
 
Encoding
boolean
 
Z
byte
 
B
char
 
C
class or interface
 
Lclassname;
double
 
D
float
 
F
int
 
I
long
 
J
short
 
S
クラスまたはインタフェース名classnameは、上で指定したクラスのバイナリ名です.
例:
 String.class.getName()
     returns "java.lang.String"
 byte.class.getName()
     returns "byte"
 (new Object[3]).getClass().getName()
     returns "[Ljava.lang.Object;"
 (new int[3][4][5][6][7][8][9]).getClass().getName()
     returns "[[[[[[[I"
 

戻り値:
このオブジェクトが表すクラスまたはインタフェース名.
7.Classの他の方法
1)Class.新Instance()は、選択したClassオブジェクトを使用してクラスの新しいインスタンスを生成します.デフォルト(パラメータなし)のクラスコンストラクタを呼び出して新しいオブジェクトを生成します.したがってnewInstance()を使用して作成されるクラスにはデフォルトのコンストラクタが必要です.newInstance()では、元のオブジェクトが存在しない場合に、新しいオブジェクトを作成できます.
newInstance()を使用してオブジェクトをインスタンス化します.
結果:
Loading Point
2)Class.isInstance()メソッドはinstanceof演算子を動的に呼び出す方法を提供する.
3)Class.getInterfaces()メソッドは、あるClassオブジェクトに含まれるインタフェースを表すClassオブジェクトの配列を返します.
4)Classオブジェクトがある場合は、getSuperclass()で直接ベースクラスを取得できます.このメソッドはもちろんClass参照を返すので、ベースクラスをさらにクエリーできます.これは、実行時にオブジェクトの完全なクラス階層を見つけることができることを意味します.
5)Classクラスは反射の概念をサポートし、Javaに付随するライブラリjava.lang.reflectには、Field、Method、Constructorクラス(各クラスにメンバーインタフェースが実装されている)が含まれています.これらのタイプのオブジェクトは、JVMによって実行時に作成され、未知のクラスに対応するメンバーを表すために使用されます.これにより、Constructorを使用して新しいオブジェクトを作成し、get()メソッドとset()メソッドでFieldオブジェクトに関連付けられたフィールドを読み取り、修正し、invoke()メソッドでMethodオブジェクトに関連付けられたメソッドを呼び出すことができます.また、getFields()、getMethods、getConstrucotrs()メソッドを呼び出し、フィールド、メソッド、コンストラクタを表すオブジェクトの配列を返すこともできます.
8.反射APIを利用して未知のクラスの構造方法と方法を観察する
package com.zj.sample;
 
class Point {
    static {
       System.out.println("Loading Point");
    }
 
    int x, y;
}
 
class ClassTest {
    public static void main(String[] args) {
 
       try {
           Class c = Class.forName("com.zj.sample.Point");
           Point pt = (Point) c.newInstance();
       } catch (Exception e) {
           e.printStackTrace();
       }
 
    }
}

結果:
Loading Point
com.zj.sample.Point(int,int)
void com.zj.sample.Point.output()
9.クラスのインスタンスを動的に呼び出す(pointという名前は全く現れない)
package com.zj.sample;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
 
class Point {
    static {
       System.out.println("Loading Point");
    }
 
    int x, y;
 
    void output() {
       System.out.println("x=" + x + "," + "y=" + y);
    }
 
    Point(int x, int y) {
       this.x = x;
       this.y = y;
    }
}
 
class ClassTest {
    public static void main(String[] args) {
       
       try {
           Class c = Class.forName("com.zj.sample.Point");
           Constructor[] cons = c.getDeclaredConstructors();
           Class[] params = cons[0].getParameterTypes();//           
           Object[] paramValues = new Object[params.length];//         
           for (int i = 0; i < params.length; i++) {
              if (params[i].isPrimitive())//   class             
              {
                  paramValues[i] = new Integer(i);
              }
           }
           Object o = cons[0].newInstance(paramValues);//          
           Method[] ms = c.getDeclaredMethods();//     
           ms[0].invoke(o, null);//         (output      ,null)
       } catch (Exception e) {
           e.printStackTrace();
       }
  }
}

結果:
Loading Point
x=0,y=1