Java反射粗談

反射的概述:

JAVA反射機制是在運行時將任何一個類的內部信息暴露出來,例如這個類的所有屬性和方法;並且對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。

 

  反射是java中一種強大的工具,能夠使我們很方便的創建靈活的代碼,這些代碼可以再運行時裝配,無需在組件之間進行源代碼鏈接。但是反射使用不當會成本很高!

 

 

使用方法:

java.lang.Class:是反射的源頭
通過運行時類的對象,調用其getClass方法,返回其運行時類
正常的順序時通過類構建對象,反射是通過對象找到其所對應的類,進而調用這個類

 

創建的Persion類:包含註解、集成、接口、私有屬性、私有方法等。

package D19;

/**
 * @Author: wj
 * @Date: 2018/11/25 8:35
 * @Version 1.0
 */

@MyAnnotation(value = "annotation")
public class Persion extends Creature<String> implements Comparable,MyInterface{
    public  String name;
    private  int age;

    public Persion(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Persion() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


    @MyAnnotation(value = "123")
    public void show(){
        System.out.println("我是一個人");
    }


    private void display(String nation){
        System.out.println("我的國籍是:"     +nation);
    }


    public static void info(){
        System.out.println("中國人");
    }

    @Override
    public String toString() {
        return "Persion{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public int compareTo(Object o) {
        return 0;
    }
}

 

 


 

 

 


 

 1.

 

一.獲取Class的四種方法:

1. 調用運行時類本身

Class clazz1 = Persion.Class;

System.out.print(clazz1.getName());

2. 通過運行時類的對象創建

Persion persion = new Persion();

Class clazz2 = persion.getClass();

System.out.print(clazz2.getName());

 

3.通過運行時類的全類名路徑

Class clazz3 = Class.forName("D19.Persion");

System.out.print(clazz3.getName());

4.通過類加載器

ClassLoader  classLoader = this.getClass().getClassLoader();

Class clazz4 = classLoader.loadClass("D13.Persion");

System.out.print("clazz4.getName()");

 

 

二.Class 的運用

1.獲取運行時類的屬性:

屬性的權限有別,有public、private、protected,不同權限的屬性獲取方法不同

下面提供兩種方法:

  //獲取運行時類的屬性
    @Test
    public void test1(){
        Class clazz = Persion.class;
        //getFields 只能獲取到運行時類及其父類中權限爲public的
        Field[] fields = clazz.getFields();


        //getDeclaredFields只能獲取到運行時類本身聲明的所有屬性,包括private
        Field[] fields2 = clazz.getDeclaredFields();
        for(int i =0 ; i<fields2.length;i++){
            System.out.println(fields2[i].getName());
        }
    }

2.各個屬性的特徵,包括權限修飾符、類型、變量名都可通過Class獲取

  //屬性有 權限修飾符  類型  變量名
    //獲取屬性各個部分的內容
    @Test
    public void test2(){
    //getDeclaredFields只能獲取到運行時類本身聲明的所有屬性
        Class clazz = Persion.class;
        Field[] fields2 = clazz.getDeclaredFields();
        for(Field f:fields2){
            //1.獲取每個屬性的權限修飾符
            int i = f.getModifiers();
            String str1 = Modifier.toString(i);
            System.out.println(str1);

            //2.獲取每個屬性的變量類型
            Class type = f.getType();
            System.out.println(type.getName());

            //3.獲取每個屬性的變量名
            System.out.print(f.getName());
            System.out.println();
        }
    }

3.獲取運行時類中的各種方法,同屬性一樣,不同權限的方法獲取形式不同

與屬性類似,獲取方法也分爲兩種

    @Test
    public void test3(){
        Class clazz = Persion.class;
        //1.獲取運行時類及其父類包括Object中所有的聲明爲Public的方法
        Method[] methods = clazz.getMethods();
        for(Method m :methods){
            System.out.println(m);
        }

        //2.獲取運行時類自身的方法不包括父類的,其中也包含權限爲private的
        methods = clazz.getDeclaredMethods();
        for(Method m :methods){
            System.out.println(m);
        }

    }

4.方法其他特徵的獲取,包括註解、權限修飾符、返回值類型、方法名、形參列表、拋出的異常等

以下通過Method[] methods = clazz.getMethods();獲取

 //註解,權限修飾符,返回值類型,方法名,形參列表,拋出的異常
    @Test
    public void test4(){
        Class clazz =Persion.class;
        Method[] methods = clazz.getDeclaredMethods();
        for(Method m :methods){
            //1.獲取註解
           Annotation[] ann = m.getAnnotations();
            System.out.print(ann);

            //2.權限修飾符
            System.out.print(Modifier.toString(m.getModifiers()));

            //3.返回值類型
            Class returnType = m.getReturnType();
            System.out.print(returnType.getName()+" ");

            //4.方法名
            System.out.print(m.getName()+" ");

            //5.形參列表
            System.out.print("(");
            Class[] params = m.getParameterTypes();
            for(Class p:params){
                System.out.print(p.getName());
            }
            System.out.print(")");

            //6.異常類型

            Class[] exceptions = m.getExceptionTypes();
            if(exceptions.length!=0){
                System.out.println("throws ");
            }
            for(Class e:exceptions){
                System.out.print(e.getName());
            }

            System.out.println();
        }
    }

 

5.類的泛型獲取(JDBC常用)

   //獲取父類泛型(JDBC用到)
    @Test
    public void test5() throws ClassNotFoundException {
        Class clazz = Class.forName("D19.Persion");
        //獲取帶泛型的父類
        Type type = clazz.getGenericSuperclass();
        ParameterizedType param = (ParameterizedType) type;
        Type[] args = param.getActualTypeArguments();
        System.out.println(((Class)args[0]).getName());
    }

6.獲取實現接口


    //獲取實現的接口
    @Test
    public void test6(){
        Class clazz = Persion.class;
        Class[] interfaces = clazz.getInterfaces();
        for(Class i:interfaces){
            System.out.println(i.getName());
        }
    }

 

 

7.通過Class創建對象,併爲屬性賦值,以及調用各類方法

1)通過無參構造器創建

   //使用反射創建對象,調用其中的方法(運行時類)
    @Test
    public void testReflection() throws Exception{
        Class<Persion> clazz = Persion.class;
        //1.創建clazz對應的運行時類(Persion)的對象
        Persion p =  clazz.newInstance();//必須有無參的構造方法
        System.out.println(p);
        //2.調用屬性
        Field field1 = clazz.getField("name");//public屬性
        //私有屬性調用
        Field field2 =clazz.getDeclaredField("age");
        field2.setAccessible(true);//關鍵
        field1.set(p,"L");
        field2.set(p,22);
        System.out.println(p);

        //3.使用反射調用類的方法
        Method method1 = clazz.getMethod("show");//public方法
        method1.invoke(p);

        //帶參數的以及私有的(private)方法
        Method method2 = clazz.getDeclaredMethod("display", String.class);
        method2.setAccessible(true);//關鍵
        //爲參數賦值(注意invoke可變參數)
        method2.invoke(p,"China");


        //帶返回值的
        Method method3 = clazz.getMethod("toString");
        Object returnVal = method3.invoke(p);
        System.out.println(returnVal);

        //靜態方法
        Method method4 = clazz.getMethod("info");
        method4.invoke(p);
        //也可以不用太對象
        method4.invoke(Persion.class);
    }

2)調用指定構造器


    //調用指定構造器
    @Test
    public void test8() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        String className = "D19.Persion";
        Class clazz = Class.forName(className);
        Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
        cons.setAccessible(true);
        Persion p = (Persion) cons.newInstance("bxklx",20);
        System.out.println(p);
    }

 

8.通過ClassLoder讀取配置文件

配置文件:

user=root;
password=123

讀取方法:

 ClassLoader classLoader = this.getClass().getClassLoader();
        InputStream is =  classLoader.getResourceAsStream("Jdbc.properties");
        Properties properties = new Properties();
        properties.load(is);
        String user =  properties.getProperty("user");
        System.out.println(user);

結果:

 

以上就是我學習JAVA反射時用到的方法,對於反射用到的地方特別多,尤其是閱讀框架源碼時候,此外在通過Sql查詢數據庫獲得對象時,也可通過反射構建實體對象,並未對象賦值。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 



 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章