黒馬プログラマー-Javaベース強化の反射

17159 ワード

----------androidトレーニング、javaトレーニング、あなたとの交流を期待しています!--------
一、Class類(反射の基石)
1、反射とは何かを知る前に、Classというクラスを知ることができます.Person類は人間を代表しています
実例の対象は張三、李四という具体的な人で、Javaプログラムの各Javaクラスは同じものに属し、このようなものを記述するJavaクラス名はClassである.つまり、
  • 人----->Perosn
  • Javaクラス----->Class
  • 2、ClassクラスはJavaクラスを表し、各インスタンスオブジェクトはこれらのインスタンスのメモリ内のバイトコードに対応する.
    メモリに3つのバイトコードが存在する場合、この3つのバイトコードはClassクラスのインスタンスオブジェクトです.
    JavaプログラムでClassオブジェクトを取得するには、通常、次の3つの方法があります.
    ①ClassクラスのforName(String clazzName)静的アクセスを使用します.このメソッドでは、クラスの全限定クラス名(完全なパッケージ名である必要があります):
    Class.forName("  "),  ,Class.forName("java.util.Date");

    ②クラスのクラス属性を呼び出し、クラスに対応するクラスオブジェクトを取得します.たとえば、Person.classはPersonクラスに対応するClassオブジェクトを返します.
      .class,  ,System.class

    ③オブジェクトgetClass()メソッドを呼び出します.このメソッドはjava.lang.Objectクラスのメソッドの1つであるため、すべてのJavaオブジェクトがメソッドを呼び出すことができ、このメソッドはオブジェクトが属するクラスに対応するClassオブジェクトを返します.
      .getClass(),  ,new Date().getClass()

       第2の方法は、反射応用において最も一般的であり、以下の2つの利点を有する.
  • コードの方が安全です.プログラムはコンパイル段階でアクセスするClassオブジェクトが存在するかどうかをチェックし、プログラムのパフォーマンスが向上します.
  • この方法は、メソッドを呼び出す必要がないため、よりパフォーマンスが向上する.

  •    1つ目は、文字列が伝達されているのでClassNotFoundException異常が放出される可能性がありますが、この方法は文字列が伝達されているので、外部から伝達されたパラメータとして使用することができます.
    3、Javaには9つの事前定義Classインスタンスオブジェクトがあります.
    boolean,byte,char,short,int,long,float,doubleに特殊なvoidを追加
    簡単なテストを行います.
    package itheimareview;
    class ReflectTest1
    {
        public static void main(String[] args)
        {
            String str1 = "abc";
            Class cls1 = str1.getClass();
            Class cls2 = String.class;
            Class cls3 = Class.forName("java.lang.String");
            System.out.println(cls1 == cls2);//true
            System.out.println(cls1 == cls3);//true
            System.out.println(cls1.isPrimitive());//false
            System.out.println(int.class.isPrimitive());//true
            System.out.println(int.class == Integer.class);//false
            System.out.println(void.class.isPrimitive());//true
            System.out.println(int.class == Integer.TYPE);//true
            System.out.println(int[].class.isPrimitive());//false
            System.out.println(int[].class.isArray());//true
        }
    }

    4、注意:
       ソースプログラムに表示されるタイプであれば、それぞれのClassインスタンスオブジェクト、例えばint[],void...
    二、反射(Reflect)
    1、反射主はJavaクラスの様々な成分をそれ自体を含んで対応するjavaクラスにマッピングする.パッケージ、メンバー変数、メソッド、構築方法、注釈などの情報は、Package、Field、Method、Contructor、Annotationなどのクラスのインスタンスオブジェクトで表される可能性があります.
    2、クラスの各メンバーは、対応する反射APIクラスのインスタンスオブジェクトで表すことができ、Classクラスを呼び出す方法でこれらのインスタンスオブジェクトを得ることができ、これらのインスタンスオブジェクトは、メソッド、構築方法、メンバー変数など、それぞれの成分を有し、その後、これらの成分に対応するクラスでさらに操作することができる.
    3、Class.newInstance()方法:
    例:String obj=(String)Class.forName("java.lang.String").newInstance();このメソッドの内部には、デフォルトのコンストラクションメソッドが得られ、その後、このコンストラクションメソッドを使用してインスタンスオブジェクトが作成されます.
       思考:この方法の内部の具体的なコードはどのように書かれていますか?
       キャッシュメカニズムを使用して、デフォルトのコンストラクションメソッドのインスタンスオブジェクトを保存します.
    4、具体的な操作は例で説明する:
    例1:
    Constructorクラス:クラスの構造方法を表します.
    反射したい場合は、次のコードを実現します.
    //new String(new StringBuilder("abc"));
    package itheimareview;
    import java.lang.reflect.Constructor;
    class ReflectTest2
    {
        public static void main(String[] args)
        {  
            /*
               String   ,   String       ,       String 
                  ,    getConstructor()               , 
                                  Class  (        )
                 Constructor  
            */
            Constructor constructor1 = String.class.getConstructor(StringBuilder.class);
            /*
                       ,new StringBuilder("abc")           StringBuilder
              ,  Constructor  newInstance()  ,               ,
                    StringBuilder  ,           :
            String(StringBuilder builder)
                              ,       jvm    
            “String.class.getConstructor(StringBuilder.class);”         
                constructor1,              。
            */
            String str2 = (String)constructor1.newInstance(new StringBuilder("abc"));
            //      
            System.out.println(str2.charAt(2));//c
            //       ,                     。
            StringBuilder sBuilder = new StringBuilder("abc");
            Class parameterTypes = sBuilder.getClass();
            Constructor constructor2 = String.class.getConstructor(parameterTypes);
            String str3 = (String)constructor2.newInstance(sBuilder);
            System.out.println(str3)//abc
        }
    }

    例2:
    Fieldクラス:クラスのメンバー変数を表します.
    まず、メンバー数のあるクラスを定義します.
    package itheimareview;
    public class ReflectPoint1
    {  
        private int x;
        public int y;//    ,       。
        public ReflectPoint(int x, int y)
        {
            super();
            this.x = x;
            this.y = y;
        }
    }

    テストクラス:
    import java.lang.reflect.Field;
    class ReflectTest3
    {
        public static void main(String[] args)
        {  
            ReflectPoint pt1 = new ReflectPoint(3, 5);
            Field fieldY = pt1.getClass().getField("y");
            /*
            fieldY     ? 5, ,fieldY         ,     ,
                          
            */
            System.out.println(fieldY);//public int itheimareview.ReflectPoint.y
            System.out.println(fieldY.get(pt1));//5
            /*
                      :NoSuchFieldException,   x     ,   ,
            java       ,    ,getDeclaredField();
            */
            //Field fieldX = pt1.getClass().getField("x");
            Field fieldX = pt1.getClass().getDeclaredField("x");
                                                                                          
            /*
                               :IllegalAccessException  
                    ,      。      ,     :     
                    ,    100W   ,     ,          
                   100W,                     ?
                   。java        setAccessible(true);     
            Field    AccessibleObject   (AccessibleObject Constructor,Field,
            Method    )   true                  Java       。
                     
            */
            fieldX.setAccessible(true);//    
            System.out.println(fieldX.get(pt1));//3
        }
    }

    例3:
    Methodクラスは、クラス内のメンバーメソッドを表します.
    package itheimareview;
    import java.lang.reflect.Method;
    class ReflectTest4
    {
        public static void main(String[] args)
        {  
            Method methodCharAt = String.class.getMethod("charAt", int.class);
            /*
            invoke         ,         ,  ,  ,     ,
                         ,              ,      
                  ,         ,            ,      
                  ,              ,      ,      
                 。          ,     ,           
            */
            System.out.println(methodCharAt.invoke(str1, 1));//b       
            //Object[] obj  = new Object[]{"abc",1,"fa"};
            //JDK1.4      。
            System.out.println(methodCharAt.invoke(str1, new Object[]{2}));//c
                                                                                    
            /*
                 Method   invoke()         null,   Method  
                      ,      :
            */
            char[] chs = new char[]{'a','b','c','d'};
            //String.valueOf(chs);
            Method methodValueOf = String.class.getMethod("valueOf", char[].class);
            System.out.println(methodValueOf.invoke(null, chs));//abcd
            System.out.println("---------------------------------------------");
            //    
            //TestArguments.main(new String[]{"111","222","333"});
            String startingClassName = args[0];
            Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
            /*
              :     Object?
               JDK1.4 1.5JDK invoke  :
            Jdk1.5:public Object invoke(Object obj,Object... args)
            Jdk1.4:public Object invoke(Object obj,Object[] args)
            main       String[]       , new String[]{"111","222","333"}; ,
            java                     。         :
            IllegalArgumentException                         。
            */
            mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
            // 
            mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});
        }
    }

    以上の3つのクラスはjava.lang.reflect.AccessibleObjectクラスの3つの直接サブクラスです.
    三、配列の反射:
    1.同じ次元と要素タイプを持つ配列は、同じタイプ、つまり同じClassインスタンスオブジェクトに属します.
    2.配列を表すClassインスタンスオブジェクトのgetSuperClass()メソッドが返す親は、Objectクラスに対応するClassです.
    3.基本タイプの一次元配列はObjectタイプとして使用でき、Object[]タイプとして使用できない.基本タイプ以外の1次元配列は、ObjectタイプとしてもObject[]タイプとしても使用できます.
    4、Arrayクラス:Java配列を動的に作成してアクセスする方法を提供します.
    5、具体的な応用例は以下の通りである.
    package itheimareview;
    import java.util.Arrays;
    import java.lang.reflect.Array;
    class ReflectTest5
    {
        public static void main(String[] args)
        {
            int[] a1 = new int[]{1,2,3};
            int[] a2 = new int[4];
            int[][] a3 = new int[2][3];
            String [] a4 = new String[]{"a","b","c"};
            System.out.println(a1.getClass().equals(a2.getClass()));//true
            System.out.println(a1.getClass() == a2.getClass());//true
            System.out.println(a1.getClass().equals(a3.getClass()));//false
            System.out.println(a1.getClass().equals(a4.getClass()));//false
            /*
                        ?
                :Incompatible operand types Class<capture#17-of ? extends int[]> and
            Class<capture#18-of ? extends String[]>
                 (    1.7)。
            System.out.println(a1.getClass() == a3.getClass());
            System.out.println(a1.getClass() == a4.getClass());
            */
            System.out.println("----------------------------------------------------");
            System.out.println(a1.getClass().getSuperclass().getName());
            System.out.println(a3.getClass().getSuperclass().getName());
            System.out.println(a4.getClass().getSuperclass().getName());
    //               Object
            Object aObj1 = a1;//  int[] Object
            Object aObj2 = a4;//  String[] Object
    //      Object[] aObj3 = a1;   ,  int  Obejct
            Object[] aObj4 = a3;//  int[] Object
            Object[] aObj5 = a4;//  String Object      
            System.out.println(a1);//[I@f47396
            System.out.println(a4);//[Ljava.lang.String;@d0af9b
            System.out.println("----------------------------------------------------");    
            /*
                   int         ?
                 JDK1.4 JDK1.5Arrays asList     :
            1.4:public static List asList(Object[] a);
            1.5: publci static <T> List <T> asList(T... a);
                 String  ,   JDK1.4   ,     JDK1.4   ,  
                 int    ,  JDK1.4   (int[] a1 = new int[]{1,2,3};  
            Object[] aObj3 = a1;   ),      JDK1.5   
                 int[]    Object   ,     Object     。
            */
            System.out.println(Arrays.asList(a1));//[[I@d0af9b]
            System.out.println(Arrays.asList(a4));//[a, b, c]
            System.out.println("----------------------------------------------------");
                                                         
            Object obj = "xyz";
            printObject(obj);
            printObject(a1);
            /*
                  ,            ,       ,      ,    。
                       。
            */
            private static void printObject(Object obj)
            {
                /*          Class  ,    isArray()       
                      。*/
                Class clazz = obj.getClass();
                if (clazz.isArray())
                {
                    //Array.getLength(Object array):  int              
                    int len = Array.getLength(obj);
                    for (int i = 0; i < len; i++)
                    {
                        //get(Object array, int index):               。
                        System.out.println(Array.get(obj, i));
                    }
                }
                else
                {
                    System.out.println(obj);
                }
            }
        }
    }

    四、汎用と反射
    1、汎用型の反射における応用は、反射中に実行されるClassCastException異常をコンパイル時期に移行するほか、反射によって汎用型情報を取得する.反射による汎用情報の取得は比較的重要な知識点である.
    2、例えば:汎用オブジェクト付きの汎用タイプを抽出したいのですが、一般的な方法ではできないのは明らかです.汎用タイプはコンパイル時期にタイプ化されたからです.この時、私たちは反射を使います.次の2つの方法で取得します.
    ①方式一:
       メソッドによる取得:
       説明:MethodメソッドにはgetGenericParameterType()のメソッドがあるため、その戻り値タイプはType[]であり、TypeはJavaプログラミング言語のすべてのタイプの共通の高度なインタフェースである.これらには、元のタイプ、パラメトリックタイプ、配列タイプ、タイプ変数、および基本タイプが含まれます.その下にParameterizedType(パラメトリックタイプを表す)というサブクラスがあります.このサブクラスには3つの方法があります.
  • Type[]getActualType Arguments():このタイプの実際のタイプのパラメータを表すTypeオブジェクトの配列を返します.
  • Type getOwnerType():このタイプがメンバーの1つであることを示すTypeオブジェクトを返します.
  • Type getRawType():このタイプのクラスまたはインタフェースを宣言することを示すTypeオブジェクトを返します.

  •    次のコードで示すように、これらの方法で汎用情報を取得できます.
    package itheimareview;
    import java.lang.reflect.Method;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.Map;
    public class GenericTest
    {
        public static void main(String[] args) throws Exception
        {
            // TODO Auto-generated method stub
            Method applyMethod = GenericTest.class.getMethod("applyMap", Map.class);
            Type[] types = applyMethod.getGenericParameterTypes();
            for (Type type : types)
            {
                if (type instanceof ParameterizedType)
                {
                    ParameterizedType pType = (ParameterizedType)type;
                    //     :java.util.Map<java.lang.String, java.lang.Integer>
                    System.out.println(pType);     
                    //     :sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
                    System.out.println(pType.getClass().getName());
                    Type[] types2 = pType.getActualTypeArguments();
                    /*                :
                    class java.lang.String
                    class java.lang.Integer*/
                    for (Type type2 : types2)
                    {
                        System.out.println(type2);
                    }
                }
                else
                {
                    System.out.println("        !");
                }
            }
                    
        }          
        public static void applyMap(Map<String,Integer> map)
        {  
            System.out.println("          ");
        }  
    }

    ②方法2:
       フィールドによって取得され、プロセスは同じです.
    package itheimareview;
    import java.lang.reflect.Field;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.Map;
    public class GenericTest2
    {
        //           
        private Map<String, Integer> value;
        public static void main(String[] args) throws Exception
        {
            //       Class,      Field
            Class<GenericTest2> clazz = GenericTest2.class;
            //    
            Field field = clazz.getDeclaredField("value");
            //      ,           
            //Field field = clazz.getField("value");
            //    Type
            Type gType = field.getGenericType();
            if (gType instanceof ParameterizedType)
            {
                ParameterizedType pType = (ParameterizedType)gType;
                //     :java.util.Map<java.lang.String, java.lang.Integer>
                System.out.println(pType);     
                //     :sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
                System.out.println(pType.getClass().getName());
                Type[] types = pType.getActualTypeArguments();
                /*                :
                class java.lang.String
                class java.lang.Integer*/
                for (Type type : types)
                {
                    System.out.println(type);
                }
            }
        }
    }

    ----------androidトレーニング、javaトレーニング、あなたとの交流を期待しています!--------
    本文は“汐朔”のブログから出て、転載して作者と連絡してください!