java筆記--反射機制之基礎總結與詳解


一.反射之實例化Class類的5種方式:

 

java的數據類型可以分為兩類,即引用類型和原始類型(即基本數據類型)。
對於每種類型的對象,java虛擬機會實例化不可變的java.lang.Class對象。
它提供了在運行時檢查對象屬性的方法,這些屬性包括它的成員和類型信息。

 

更重要的是Class對象是所有反射API的入口。

 

Class類是泛型類,可以使用@SuppressWarnings("unchecked")忽略泛型或者使用Class<V>類型。

 

獲得Class對象的5種方式:


1."Object.getClass()"   : 如果一個類的對象可用,則最簡單的獲得Class的方法是使用Object.getClass()。
                                    當然,此方式只對引用類型有效。

2. ".class"------------- : 如果類型可用但沒有對象,則可以在類型后加上".class"來獲得Class對象。這也是使原始類型
                                    獲得Class對象最簡單的方式:
3."Class.forName()"---:  如果知道類的全名,則可以使用靜態方法Class.forName()來獲得Class對象,它不能用在原始類型上,

                                    但是可以用在原始類型數組上。(注:此方式會拋出ClassNotFoundException異常)
4. "包裝類的TYPE域"-----:  每一個原始類型和void都有包裝類。利用其TYPE域就可以獲得Class對象。


5."以Class為返回值的方法": 如獲取內部類的getDeclaredClasses()方法,此時返回一個對象數組

 --支持知識共享,轉載請標注地址"http://www.cnblogs.com/XHJT/p/3915221.html  "——和佑博客園,謝謝~~--

代碼實例:

package com.xhj.reflection_excetion;

/**
 * 反射之實例化Class類的5種方式
 * 
 * @author XIEHEJUN
 * 
 */
public class InstantiateClassObject {

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.print("第一種方式--用Object.getClass()方法獲取到的String類的對象為: ");
        Class class1 = new String().getClass();
        System.out.println(class1.getName());    
        
        System.out.print("第二種方式--用.class()方法獲取到的String類的對象為: ");
        class1 = String.class;
        System.out.println(class1.getName());
        
        System.out.print("第三種方式--用.forName()方法獲取到的String類的對象為: ");
        class1 = Class.forName("java.lang.String");
        System.out.println(class1.getName());
        
        System.out.print("第四種方式--用包裝類的TYPE域獲取到的Integer類的對象為: ");
        class1 = Integer.TYPE;
        System.out.println(class1.getName());
        
        System.out.println("第五種方式--用getDeclaredClasses()獲取String類的內部類對象:");
        Class<?>[] clazz = new String().getClass().getDeclaredClasses();
        for (Class<?> class2 : clazz) {
            System.out.println("\t"+class2);
        }
        

    }

}

結果為:

結果


注:除了java.lang.reflect.ReflectPermission和java.lang.reflect包外,所有類都沒有公共的
構造方法。為了獲得這些類的對象,必須使用Class類中適當的方法,對於不同的數據類型,Class
對象的獲得方式是不同。

 

二.反射之查看類的定義:

 

   通常類的聲明包括常見修飾符(public,protected,private,abstract,static,final,strictfp等)、
    類的名稱、類的泛型參數、類的繼承類(實現的接口)、類的注解等信息。

   
    Class類的實例表示正在運行的Java應用程序中的類和接口:
    枚舉是一種類,注釋是一種接口。
    每一個數組屬於被映射為Class對象的一個類,所有具有相同元素類型和維數的數組都共享該Class對象;
    基本數據類型和關鍵字void也表示為Class對象。
    Class沒有公共的構造方法。
    Class對象是在加載類時由Java虛擬機以及通過調用類加載器中的defineClass方法自動構造的。
   
    Class類常用方法:
    forName(String className)-: 根據給定的名稱獲得Class對象
   getAnnotations()------------: 返回此Class對象上存在的注釋
   getCanonicalName() --------: 返回Java Language Specification 中所定義的底層類的規范化名稱
    getGenericInterfaces()------: 返回泛型形式的對象類所實現的接口
    getGenericSuperclass() -----: 返回泛型形式的對象類所直接繼承的超類
    getModifuers() --------------: 返回此類或接口以整數編碼的Java語言修飾符
    getTypeParameters() -------: 按聲明順序返回TypeVariable對象的一個數組


   注:Java語言預定義的注解只有@Deprecated可以在運行時獲得。   
   
實例代碼:

package com.xhj.reflection_excetion;

import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

/**
 * 查看類的定義
 * 
 * @author XIEHEJUN
 * 
 */
public class CheckClassStatement {

    public static void main(String[] args) throws ClassNotFoundException {
        Class<?> classtest = Class.forName("java.util.ArrayList");
        System.out.println("1.根據給定的名稱獲得Class對象:" + classtest.getName());
        Annotation[] annotations = classtest.getAnnotations();
        System.out.print("2.獲取此對象上的注解為:");
        if (annotations.length > 0) {
            for (Annotation annotation : annotations) {
                System.out.println(annotation + "\t");
            }
        } else {
            System.out.println("空");
        }

        System.out.println("3.獲得Java語言規范化名稱:" + classtest.getCanonicalName());

        System.out.println("4.獲取類上的修飾符:共有" + classtest.getModifiers()
                + "個,為: " + Modifier.toString(classtest.getModifiers()));

        TypeVariable<?>[] typeV = classtest.getTypeParameters();
        System.out.print("5.在對象上獲取到的泛型是:");
        if (typeV.length > 0) {
            for (TypeVariable<?> typeVariable : typeV) {
                System.out.println(typeVariable);
            }
        } else {
            System.out.println("空");
        }

        System.out.println("6.在對象上獲取到的接口為:");
        // 使用getInterfaces()不包含泛型;使用getGenericInterfaces包含泛型
        Type[] intefaces = classtest.getGenericInterfaces();
        if (intefaces.length > 0) {
            for (Type type : intefaces) {
                System.out.println("\t" + type);
            }
        } else {
            System.out.println("空");
        }
        Class class2 = classtest.getSuperclass();
        System.out.print("7.在對象上獲取直接繼承類:");
        if (class2 != null) {
            System.out.println(class2);
        } else {
            System.out.println("空");
        }

    }
}

結果為:

結果


注:getSuperclass()方法也不能獲得有泛型信息的父類

 

三.反射之獲得Class對象表示實體的名稱

 

對於不同類型的對象,其Class對象的名稱是不同的,反過來說就是從這個名稱就可以知道該對象的類型。

注:
    1.如果此類對象表示的是非數組類型的引用類型,則返回該類的二進制名稱。
    2.如果此類對象表示一個基本類型或者void,則返回其對應的Java語言的關鍵字的字符串。
    3.如果此類對象表示一個數組類,名字的內部形式為"[元素編碼",其深度為幾維,就有幾個"["。
        其元素類型編碼為:
        ——————————————————————————————————————————————————
           元素類型                       編 碼          
           boolean                         Z
           byte                              B
           char                              C
           short                             S
           int                                 I
           float                              F
           double                           D
           long                              J
           class or interfaces       Lclassname(即當元素是引用類型或者接口的時候,編碼為"L+類名")
        ____________________________________________________

實例代碼:

package com.xhj.reflection_excetion;

/**
 * 獲取對象實體的名稱
 * 
 * @author XIEHEJUN
 * 
 */
public class GetClassEntityName {
    /**
     * 數組元素類型編碼為:
     * 元素類型                       編碼 
     * boolean                     Z 
     * byte                       B 
     * char                       C 
     * short                      S 
     * int                        I 
     * float                      F 
     * double                     D 
     * long                       J 
     * class or interfaces    Lclassname(即當元素是引用類型或者接口的時候,編碼為"L+類名")
     */
    public static void main(String[] args) {
        System.out.println("獲取非數組類型的引用類型,返回該類的二進制名稱: "
                + new String().getClass().getName());
        System.out.println("獲取基本類型,返回其對應的Java語言的關鍵字的字符串: "
                + int.class.getName());
        System.out.println("獲取void類型,返回其對應的Java語言的關鍵字的字符串: "
                + void.class.getName());
        System.out.println("獲取一維數組類型的基本類型,返回'[+元素編碼': "
                + new int[2].getClass().getName());
        System.out.println("獲取一維數組類型的引用類型,返回'[+元素編碼': "
                + new String[2].getClass().getName());
        System.out.println("獲取二維數組類型的基本類型,返回'[+元素編碼': "
                + new int[2][3].getClass().getName());
        System.out.println("獲取二維數組類型的引用類型,返回'[+元素編碼': "
                + new String[2][3].getClass().getName());
        System.out.println("用getCanonicalName()獲取二維數組類型的基本類型,返回數組名稱"
                + new int[2][3].getClass().getCanonicalName());
        System.out.println("用getCanonicalName()獲取二維數組類型的引用類型,返回數組名稱"
                + new String[2][3].getClass().getCanonicalName());
    }

}

結果為:

結果

 

注:
對於數組來說,用getCanonicalName()方法可以獲取的到數組的名稱,且比較容易接受和辨認

 

四.反射之查看類的成員

 

我們要查看類的定義,首先想到的當然是API文檔,但若是找不到API文檔又該如何呢?此時就要用到Java的反射機制了。
另外我們在無法查看源代碼的情況下,也可以通過反射機制查看類的成員,包括"域,構造方法,普通方法和內部類"等。

   主要用到的方法:
    getConstructors() -------: 返回由該類對象的所有構造方法組成的數組
    getDeclaredFields() -----:  返回由該類對象的所有非繼承域組成的數組
    getDeclaredMethods() -- :  返回由該類對象的所有非繼承方法組成的數組
    getFields() -------------- :  返回由該類對象的所有公共域組成的數組
   getMethod() -------------:  返回由該類對象的所有公共方法組成的數組

代碼實例:

package com.xhj.reflection_excetion;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 查看類的成員
 * 
 * @author XIEHEJUN
 * 
 */
public class CheckClassMembers {

    public static void main(String[] args) {
        Class<?> strclass = new String().getClass();

        // 查看構造方法
        System.out.println(strclass.getName() + "的構造方法有:");
        Constructor<?>[] constructors = strclass.getConstructors();
        if (constructors.length > 0) {
            for (Constructor<?> constructor : constructors) {
                System.out.println("\t" + constructor);
            }
        } else {
            System.out.println("空");
        }
        // 查看非繼承域
        System.out.println(strclass.getName() + "的非繼承域有:");
        Field[] declaredFields = strclass.getDeclaredFields();
        if (declaredFields.length > 0) {
            for (Field field : declaredFields) {
                System.out.println("\t" + field);
            }
        } else {
            System.out.println("空");
        }

        // 查看非繼承方法
        System.out.println(strclass.getName() + "的非繼承方法有:");
        Method[] declaredMethods = strclass.getDeclaredMethods();
        if (declaredMethods.length > 0) {
            for (Method method : declaredMethods) {
                System.out.println("\t" + method);
            }
        } else {
            System.out.println("空");
        }

        // 查看所有公共域
        System.out.println(strclass.getName() + "的所有域有:");
        Field[] fields = strclass.getFields();
        if (fields.length > 0) {
            for (Field field : fields) {
                System.out.println("\t" + field);
            }
        } else {
            System.out.println("空");
        }

        // 查看所有公共的方法
        System.out.println(strclass.getName() + "的所有繼承方法有:");
        Method[] methods = strclass.getMethods();
        if (methods.length > 0) {
            for (Method method : methods) {
                System.out.println("\t" + method);
            }
        } else {
            System.out.println("空");
        }
    }

}

結果為:

(打印出來的數據太多,這里之展示部分結果~)

結果

注:對於私有域或方法,如果有安全管理器,可能會報異常。

 

五:反射之查看內部類消息

 

Class類的getDeclaredClasses()方法返回Class對象的一個數組,這些對象反映聲明為該Class對象
所表示的類的成員的所有類和接口,包括該類所聲明的公共、保護、默認(包)訪問及私有類和接口,
但不包括繼承的類和接口。若該類不將任何類或接口聲明為成員,或者該對象表示基本類型、數組類或
void,則該方法返回一個長度為0的數組。
        public Class<?> [] getDeclaredClasses() throws SecurityException

 

注:利用Class類的getDeclaredClasses()方法可以獲得一個數組,其中的每一個成員代表一個內部類的類對象。
然后我們可以像獲取普通類的信息一樣,獲取到內部類的信息。
          
代碼實例:

package com.xhj.reflection_excetion;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 查看內部類的消息
 * 
 * @author XIEHEJUN
 * 
 */
public class CheckInnerClass {

    public static void main(String[] args) {
        Class<?> clazz = new String().getClass();
        Class[] class1 = clazz.getDeclaredClasses();
        for (int i = 0; i < class1.length; i++) {
            Class<?> innerclass = class1[i];
            System.out
                    .println("================================================================");
            System.out.println("內部類" + i + "為: " + innerclass.getName());

            System.out.println("內部類" + i + "的父類為:"
                    + innerclass.getSuperclass().getName());

            System.out.print("內部類" + i + "的所有公共域為:");
            Field[] field = innerclass.getFields();
            if (field.length > 0) {
                System.out.println();
                for (Field field2 : field) {
                    System.out.println("\t" + field2);
                }
            } else {
                System.out.println("空");
            }

            System.out.print("內部類" + i + "的非繼承域為:");
            Field[] declaredfield = innerclass.getDeclaredFields();
            if (declaredfield.length > 0) {
                System.out.println();
                for (Field field2 : declaredfield) {
                    System.out.println("\t" + field2);
                }
            } else {
                System.out.println("空");
            }

            System.out.print("內部類" + i + "的所有公共方法為:");
            Method[] methods = innerclass.getMethods();
            if (methods.length > 0) {
                System.out.println();
                for (Method method : methods) {
                    System.out.println("\t" + method);
                }
            } else {
                System.out.println("空");
            }

            System.out.print("內部類" + i + "的非繼承方法為:");
            Method[] declaredmethods = innerclass.getDeclaredMethods();
            if (declaredmethods.length > 0) {
                System.out.println();
                for (Method method : declaredmethods) {
                    System.out.println("\t" + method);
                }
            } else {
                System.out.println("空");
            }

        }

    }

}

結果為:

(打印出來的數據太多,這里之展示部分結果~)

結果

 


六.反射之按繼承層次對類排序

 

Java提供了instanceof運算符來比較兩個類(或接口)之間是否存在繼承關系。
但是對於多個類來說,這種方法是很麻煩的。這時候,我們要做的應該是利用
java的反射機制來對存在繼承關系的類進行排序。

主要方法:

TreeSet<E> 是基於TreeMap的NavigableSet實現的。它使用元素的自然順序對
元素進行排序,或者根據創建set時提供的Comparator進行排序,具體取決於
使用的構造方法。本節采用Class類中的isAssignableFrom()方法來判斷當前
Class 對象所表示的類與給定的Class對象所表示的類之間的關系,若相同或
是父類則返回true,否則返回false。
   public boolean isAssignableFrom(Class<?> clazz)
   
注:Java中與排序相關的接口有Comparable和Comparator。這兩個接口通過對象之
間比較的結果--一個有符號的整數來比較對象的大小。實現任何一個接口都可
以讓對象具有排序的能力。固可以用TreeSet也可以用Arrays.sort()來進行排序。

 

代碼實例:

package com.xhj.reflection_excetion;

import java.awt.Container;
import java.util.Comparator;
import java.util.TreeSet;

import javax.swing.JComponent;
import javax.swing.JPanel;

/**
 * 比較並將類按繼承關系排序
 * 
 * @author XIEHEJUN
 * 
 */
public class CompareClasses implements Comparator<Class<?>> {

    @Override
    public int compare(Class<?> o1, Class<?> o2) {
        if (o1.equals(o2)) {
            return 0;
        } else if (o1.isAssignableFrom(o2)) {
            return -1;
        } else if (o2.isAssignableFrom(o1)) {
            return 1;
        } else {
            throw new IllegalArgumentException(o1+"和"+o2+"兩個類之間沒有聯系");
        }
    }

    public static void main(String[] args) {
        TreeSet<Class<?>> treeSet = new TreeSet<Class<?>>(
                new CompareClasses());
        System.out.println("添加類——JComponent.class");
        treeSet.add(JComponent.class);
        System.out
        .println("添加類——Container.class");
        treeSet.add(Container.class);
        System.out.println("添加類——JPanel.class");
        treeSet.add(JPanel.class);
        System.out.println("=================排序后為=====================");
        for (Class<?> class1 : treeSet) {
            System.out.println(class1);
        }
    }

}

結果為:

結果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM