java反射機制淺析

1.反射機制的概念:
主要是指程序可以訪問,檢測和修改它本身狀態或行爲的一種能力,並能根據自身行爲的狀態和結果,調整或修改應用所描述行爲的狀態和相關的語義。在java中,只要給定類的名字, 那麼就可以通過反射機制來獲得類的所有信息。

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


  類中有什麼信息,利用反射機制就能可以獲得什麼信息,不過前提是得知道類的名字。
2.反射機制的作用
在運行時判斷任意一個對象所屬的類;
在運行時獲取類的對象;
在運行時訪問java對象的屬性,方法,構造方法等。
(所有類都是class實例)


3.反射機制的優缺點
首先要搞清楚爲什麼要用反射機制?直接創建對象不就可以了嗎,這就涉及到了動態與靜態的概念。
靜態編譯:在編譯時確定類型,綁定對象,即通過。
動態編譯:運行時確定類型,綁定對象。動態編譯最大限度發揮了java的靈活性,體現了多態的應用,有以降低類之間的藕合性。

反射機制的優點:可以實現動態創建對象和編譯,體現出很大的靈活性(特別是在J2EE的開發中它的靈活性就表現的十分明顯)。通過反射機制我們可以獲得類的各種內容,進行了反編譯。對於JAVA這種先編譯再運行的語言來說,反射機制可以使代碼更加靈活,更加容易實現面向對象。

  比如,一個大型的軟件,不可能一次就把把它設計的很完美,當這個程序編譯後,發佈了,當發現需要更新某些功能時,我們不可能要用戶把以前的卸載,再重新安裝新的版本,假如這樣的話,這個軟件肯定是沒有多少人用的。採用靜態的話,需要把整個程序重新編譯一次纔可以實現功能的更新,而採用反射機制的話,它就可以不用卸載,只需要在運行時才動態的創建和編譯,就可以實現該功能。

反射機制的缺點:對性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什麼並且它 滿足我們的要求。這類操作總是慢於只直接執行相同的操作。


反射機制的示例:

所列都是class的實例

package reflect;

/**
 * 獲得一個對象完整的包名和類名
 */
 class Reflect {
     //example code
 }
class Demo {

    public static void main(String[] args) {
        //初始化Reflect
        Reflect reflect = new Reflect();
        //獲取Reflect對象的包名和類名
        System.out.println(reflect.getClass().getName());

    }
}
運行結果:

reflect.Reflect



----------
2.實例化class對象(獲取類對象的三種方式)

package reflect;

/**
* 實例化類對象,獲取類對象的三種方式
*/
class Reflect {
//example code
}
class Demo {

public static void main(String[] args) {
    Class<?> demo1 = null;
    Class<?> demo2 = null;
    Class<?> demo3 = null;

    //第一種方式
    String className = "reflect.Reflect";
    try {
        demo1 = Class.forName(className);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

    //第二種方式
    demo2 = new Reflect().getClass();

    // 第三種方式
    demo3 = Reflect.class;


    // 打印結果
    System.out.println("第一種"+demo1.getName());
    System.out.println("第二種"+demo2.getName());
    System.out.println("第三種"+demo3.getName());

}

}

運行結果:
第一種reflect.Reflect
第二種reflect.Reflect
第三種reflect.Reflect

註釋: 準確的講是一個ClassLoader下,一種類,只會有一個類對象存在,3種方式
1. Class.forName
2. Hero.class
3. new Hero().getClass()

在一個JVM中,一種類,只會有一個類對象存在。所以以上三種方式取出來的類對象,都是一樣的。


3.通過Class實例化其他類的對象
實例化Person對象初始化Person對象,並對Person屬性進行操作
注:Class.newInstance只能調用無參構造
    Constructor.newINstance只能調用有參構造

測試類代碼:

package reflect;

/**
* 通過反射獲取Person的屬性
*
* @author BxTizen
*/
public class PersonReflect {
public static void main(String[] args) {

    // 建立Class模型對象
    Class<?> demo = null;

    //獲取Person類對象,同時會初始化類的屬性
    try {
        demo = Class.forName("reflect.Person");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

    //準備一個Person類的屬性,指向null
    Person person = null;

    //通過 newInstance實例化對象
    try {
        person = (Person) demo.newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }

    //給實例化對象賦值
    person.setAge(23);
    person.setName("23333");

    //打印person的屬性
    System.out.println(person);
}

}



----------


Person實體類:
package reflect;

/**
 * 通過反射獲取Person的屬性
 *
 * @author BxTizen
 */
public class PersonReflect {
    public static void main(String[] args) {

        // 建立Class模型對象
        Class<?> demo = null;

        //獲取Person類對象,同時會初始化類的屬性
        try {
            demo = Class.forName("reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //準備一個Person類的屬性,指向null
        Person person = null;

        //通過 newInstance實例化對象
        try {
            person = (Person) demo.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        //給實例化對象賦值
        person.setAge(23);
        person.setName("23333");

        //打印person的屬性
        System.out.println(person);
    }
}
運行的結果:
Person{name='23333', age=23}


----------
4.通過Class調用其他類中的構造函數 (也可以通過這種方式通過Class創建其他類的對象)

首先,瞭解一下構造器
獲取類的構造器 
首先介紹一下Constructor類,這個類用來封裝反射得到的構造器,Class有四個方法來獲得Constructor對象
public Constructor<?>[] getConstructors() 返回類中所有的public構造器集合,默認構造器的下標爲0
public Constructor<T> getConstructor(Class<?>... parameterTypes) 返回指定public構造器,參數爲構造器參數類型集合
public Constructor<?>[] getDeclaredConstructors() 返回類中所有的構造器,包括私有
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回任意指定的構造器

獲取類的成員變量 
成員變量用Field類進行封裝,主要的方法非常的類似:
public Field getDeclaredField(String name) 獲取任意指定名字的成員
public Field[] getDeclaredFields() 獲取所有的成員變量
public Field getField(String name) 獲取任意public成員變量
public Field[] getFields() 獲取所有的public成員變量

獲取類的方法 
public Method[] getMethods() 獲取所有的共有方法的集合
public Method getMethod(String name,Class<?>... parameterTypes) 獲取指定公有方法 參數1:方法名 參數2:參數類型集合 
public Method[] getDeclaredMethods() 獲取所有的方法
public Method getDeclaredMethod(String name,Class<?>... parameterTypes) 獲取任意指定方法
(以上的瞭解一下,可以查詢javaAPI文檔詳細的)



Constructor<?> cons[]=demo.getConstructors();

//無參構造函數
Object object0 = (Object)cons[0].newInstance();
Object object1 = (Object)cons[1].newInstance(parameter);
//多參構造函數
Object object2 = (Object)cons[2].newInstance(parameter1,parameter);

構造函數取出來是有順序的,Constructor<?> cons[]=cls.getConstructors()的cons[]數組下標對應的對象類裏面的構造函數順序相反,如上例中:最後一個構造方法Person(String name, int age)對應於cons[0],第一個構造方法Person()對應於cons[3];順序不對會造成參數不正確的異常:

接下來看代碼示例:

package reflect;

import java.lang.reflect.Constructor;

public class PersonReflect2 {
public static void main(String[] args) {
Class


實體類:

package reflect;

public class Person {
private int age;
private String name;

public Person() {

}

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

public int getAge() {
    return age;
}

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

public String getName() {
    return name;
}

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

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

}


運行結果:
Person{age=0, name='null'}
Person{age=0, name='Rollen'}
Person{age=20, name='null'}
Person{age=20, name='Rollen'}


----------
5.返回一個構造類的實接口
接口類:

package reflect1;

public interface China {
public static final String name = “Rollen”;
public static int age = 20;

public void sayChina();

public void sayHello(String name, int age);

}

接口實現實體類:

package reflect1;

public class Person implements China {
private String sex;

public String getSex() {
    return sex;
}

public void setSex(String sex) {
    this.sex = sex;
}

public Person() {
}

@Override
public void sayChina() {
    System.out.println("hello ,china");
}

@Override
public void sayHello(String name, int age) {
    System.out.println(name + "  " + age);
}

}

測試類:

package reflect1;

public class Hello {
public static void main(String[] args) {
Class



----------


6.取得其他類中的父類

package reflect1;

public class Hello {
public static void main(String[] args) {
Class



----------


7.獲得其他類中的全部構造函數

package reflect1;

import java.lang.reflect.Constructor;

public class Hello {
public static void main(String[] args) {
Class

運行結果:
構造方法:  public reflect1.Person()


----------


獲取構造方法的全部:

package reflect1;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

public class Hello {
public static void main(String[] args) {
Class

運行結果:
構造方法:  public reflect1.Person(){}


----------


8.取得其他類的全部屬性,將這些整理在一起,也就是通過class取得一個類的全部框架

package reflect1;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class Hello {
public static void main(String[] args) {

    Class<?> demo = null;
    try {
        demo = Class.forName("reflect1.Person");
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("===============本類屬性========================");
    // 取得本類的全部屬性
    Field[] field = demo.getDeclaredFields();
    for (int i = 0; i < field.length; i++) {
        // 權限修飾符
        int mo = field[i].getModifiers();
        String priv = Modifier.toString(mo);
        // 屬性類型
        Class<?> type = field[i].getType();
        System.out.println(priv + " " + type.getName() + " "
                + field[i].getName() + ";");
    }
    System.out.println("===============實現的接口或者父類的屬性========================");
    // 取得實現的接口或者父類的屬性
    Field[] filed1 = demo.getFields();
    for (int j = 0; j < filed1.length; j++) {
        // 權限修飾符
        int mo = filed1[j].getModifiers();
        String priv = Modifier.toString(mo);
        // 屬性類型
        Class<?> type = filed1[j].getType();
        System.out.println(priv + " " + type.getName() + " "
                + filed1[j].getName() + ";");
    }
}

}

運行結果:

===============本類屬性========================
private java.lang.String sex;
===============實現的接口或者父類的屬性========================
public static final java.lang.String name;
public static final int age;


----------
9.通過反射調用其他類中的方法

package reflect1;

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

public class Hello {
public static void main(String[] args) {
Class


運行結果:
hello ,china
Rollen  20


----------
10.調用其他類的setget方法

package reflect1;

import java.lang.reflect.Method;

public class Hello {
public static void main(String[] args) {
Class


運行結果:
男


----------
11.通過反射操作屬性

package reflect1;

import java.lang.reflect.Field;

public class Hello {
public static void main(String[] args) throws Exception {
Class


運行結果:
男


----------
12.通過反射取得並修改數組的信息

package reflect1;

import java.lang.reflect.Array;
import java.lang.reflect.Field;

public class Hello {
public static void main(String[] args) {
int[] temp={1,2,3,4,5};
Class

運行結果:
數組類型: int
數組長度  5
數組的第一個元素: 1
修改之後數組第一個元素爲: 100


----------
13.修改數組大小通過反射

package reflect1;

import java.lang.reflect.Array;
import java.lang.reflect.Field;

public class Hello {
public static void main(String[] args) {
int[] temp={1,2,3,4,5,6,7,8,9};
int[] newTemp=(int[])arrayInc(temp,15);
print(newTemp);
System.out.println(“=====================”);
String[] atr={“a”,”b”,”c”};
String[] str1=(String[])arrayInc(atr,8);
print(str1);
}
/**
* 修改數組大小
* */
public static Object arrayInc(Object obj,int len){
Class

運行結果:
數組長度爲: 15
1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 =====================
數組長度爲: 8
a b c null null null null null 
Process finished with exit code 0


----------
14.獲取類加載器
實體類

package reflect2;

public class Demo {
//test
}

測試類:

package reflect2;

public class DemoTest {
public static void main(String[] args) {
Demo demo = new Demo();
System.out.println(“類加載器”+demo.getClass().getClassLoader().getClass().getName());
}
}

“`

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