反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性,這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。一直以來反射技術都是Java中的閃亮點,這也是目前大部分框架(如Spring/Mybatis等)得以實現的支柱。
在Java中,Class類與java.lang.reflect類庫一起對反射技術進行了全力的支持。在反射包中,我們常用的類主要有Constructor類表示的是Class 對象所表示的類的構造方法,利用它可以在運行時動態創建對象、Field表示Class對象所表示的類的成員變量,通過它可以在運行時動態修改成員變量的屬性值(包含private)、Method表示Class對象所表示的類的成員方法,通過它可以動態調用對象的方法(包含private)
一、實體對象類,用作反射操作的對象
public class Person {
public static final long serialVersionUID=1l;
public String name;
private int age;
public Person() {
System.out.println("無參構造函數,運行...");
}
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("有參構造函數,運行...");
System.out.println("name:"+this.name+",age:"+this.age);
}
public void method01(){
System.out.println("共有無參函數,運行...");
}
private void method02(){
System.out.println("私有無參函數,運行...");
}
public void method03(String name,int age){
System.out.println("公有帶參函數,name:"+name+"; age:"+age);
}
private void method04(String name,int age){
System.out.println("私有帶參函數,name:"+name+"; age:"+age);
}
}
二、獲取字節碼類的方式
/**
* @Author Loujitao
* @Date 2018/6/27
* @Time 11:32
* @Description: 第一種通過實例對象獲取字節碼類
*/
public static void function01(){
Person person=new Person();
Class c=person.getClass();
System.out.println(c);
/**結果:
* 無參構造函數,運行...
* class com.steve.reflect.Person
*/
}
public static void function02(){
//通過靜態方法獲取字節碼類
Class c=Person.class;
System.out.println(c);
/**結果:
* class com.steve.reflect.Person
*/
}
public static void function03() throws Exception{
//通過類名獲取字節碼類
Class c = Class.forName("com.steve.reflect.Person");
System.out.println(c);
/**結果:
* class com.steve.reflect.Person
*/
}
三、獲取字段(成員變量)
/**
* 獲取單個字段
*/
public static void function01(Class c) throws Exception{
//它反映此 Class 對象所表示的類或接口的指定 公共 成員字段。
Field field=c.getField("name");
//反映此 Class 對象所表示的類或接口的指定已聲明字段。 可以獲取私有的屬性
Field f=c.getDeclaredField("age");
System.out.println("name: "+field );
System.out.println("age: "+f);
/* 結果:
name: public java.lang.String com.steve.reflect.Person.name
age: private int com.steve.reflect.Person.age
*/
}
/*
* 獲取字段數組 只能獲取共有的字段
* */
public static void function02(Class c) throws Exception{
Field[] fields=c.getFields();
for (Field f:fields ) {
System.out.println(f);
}
/**結果:
* public static final long com.steve.reflect.Person.serialVersionUID
* public java.lang.String com.steve.reflect.Person.name
*/
}
/*
* 獲取字段數組 所有的
* */
public static void function03(Class c)throws Exception{
Field[] fields=c.getDeclaredFields();
for (Field f:fields ) {
System.out.println(f);
}
/**結果:
* public static final long com.steve.reflect.Person.serialVersionUID
public java.lang.String com.steve.reflect.Person.name
private int com.steve.reflect.Person.age
* */
}
四、獲取方法並執行
//獲取構造函數
public static void function01(Class c) throws Exception{
Object obj=c.newInstance();
System.out.println(obj);
Constructor ct=c.getConstructor(String.class,int.class);
Object o= ct.newInstance("steve",18);
System.out.println(o);
/*結果:
無參構造函數,運行...
com.steve.reflect.Person@1540e19d
有參構造函數,運行...
name:steve,age:18
com.steve.reflect.Person@677327b6
*/
}
//獲取方法
public static void function02(Class c)throws Exception{
Object obj=c.newInstance();
Method m=c.getMethod("method01",null);
m.invoke(obj);
Method m2=c.getDeclaredMethod("method02",null);
//將反射的對象標記爲在使用時取消默認 Java 語言訪問控制檢查的能力
m2.setAccessible(true);
//對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法。
m2.invoke(obj);
Method m3=c.getMethod("method03",String.class,int.class);
m3.invoke(obj,"steve",26);
Method m4=c.getDeclaredMethod("method04",String.class,int.class);
m4.setAccessible(true);
m4.invoke(obj,"steve",26);
}
//獲取方法數組
public static void function03(Class c)throws Exception{
//獲取共有方法
Method[] m1=c.getMethods();
for (Method m:m1) {
System.out.println(m);
}
System.out.println("----------手動分割線-------------------");
Method[] m2=c.getDeclaredMethods();
for (Method mt:m2 ) {
System.out.println(mt);
}
}