一、反射
反射:Java反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為Java語言的反射機制。
要想解剖一個類,必須先要獲取到該類的字節碼文件對象。而解剖使用的就是Class類中的方法.所以先要獲取到每一個字節碼文件對應的Class類型的對象。對於反射的操作實際上就是通過Class對象獲取:
*a、java.lang.reflect.Field:提供有關類或接口的單個字段的信息,以及對它的動態訪問權限。反射的字段可能是一個類(靜態)字段或實例字段。操作類的成員變量。
*b、java.lang.reflect.Constructor<T>:操作類的夠造函數。
*c、java.lang.reflect.Method:操作類的方法。
在學習反射基礎前先創建一個Person對象作為實例:
package com.linuxidc.org.base.relfect;
public class Person {
private String name;
int age;
public String address;
public Person() {
}
private Person(String name) {
this.name = name;
}
Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
public void show() {
System.out.println("show");
}
public void method(String s) {
System.out.println("method " + s);
}
public String getString(String s, int i) {
return s + "---" + i;
}
private void function() {
System.out.println("function");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", address=" + address
+ "]";
}
}
二、獲取類的Class對象
public static void getClassObject() throws ClassNotFoundException{
//方式一:Object的getClass()方法
Person person1=new Person();
Person person2=new Person();
Class c1=person1.getClass();
Class c2=person2.getClass();
System.out.println(person1==person2);//false
System.out.println(c1==c2);//true 不管JVM內存中有多少個對象,對於字節碼文件來說只有一份
//方式二:數據類型的靜態class屬性
Class c3=Person.class;
System.out.println(c1==c3);//true
//方式三:Class 類的靜態方法
//public static Class<?> forName(String className)throws ClassNotFoundException
Class c4=Class.forName("com.linuxidc.org.base.relfect.Person");
System.out.println(c1==c4);//true
}
三、java.lang.reflect.Constructor<T>:對象並使用Constructor類。
1、獲取Constructor對象
//獲取Class 對象所表示的類的構造方法
public static void getConstructorTest() throws Exception{
Class c4=Class.forName("com.linuxidc.org.base.relfect.Person");
//1、獲取Class 對象所表示的類所有公共構造方法
//public Constructor<?>[] getConstructors() throws SecurityException
Constructor [] cs=c4.getConstructors();
//2、獲取Class 對象所表示的類所有構造方法
//public Constructor<?>[] getDeclaredConstructors() throws SecurityException
Constructor[] cs2 =c4.getDeclaredConstructors();
//3、獲取Class對象所表示類的指定指定公共構造方法, parameterTypes 參數是 Class 對象的一個數組 ,是指定數據類型的字節碼
//public Constructor<T> getConstructor(Class<?>... parameterTypes);
Constructor cs3=c4.getConstructor();//獲取公共的無參構造方法的Constructor對象
//獲取 該 構造函數 public Person(String name, int age, String address)
Constructor cs4=c4.getConstructor(String.class,int.class,String.class);
//4、獲取Clss對象所表示類指定的構造范法官 parameterTypes 參數是 Class 對象的一個數組,它按聲明順序標識構造方法的形參類型的字節碼。
//public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes);
//獲取該構造 函數 private Person(String name) 的Constructor對象
Constructor cs5=c4.getDeclaredConstructor(String.class);
}
2、通過 Constructor 對象創建Class對象所表示類的實例
public static void createObject() throws Exception{
Class c4=Class.forName("com.linuxidc.org.base.relfect.Person");
//使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,並用指定的初始化參數初始化該實例
//public T newInstance(Object... initargs);
// Person person=new Person()
Constructor cs3=c4.getConstructor();//獲取公共的無參構造方法的Constructor對象
Object obj=cs3.newInstance();
//Person person=new Person("linuxidc", 21, "北京");
Constructor cs4=c4.getConstructor(String.class,int.class,String.class);
Object obj1=cs4.newInstance("linuxidc",21,"北京");
System.out.println(obj1);//Person [name=linuxidc, age=21, address=北京]
//實例化一個私有的構造函數 private Person(String name)
//控制java的訪問檢查
//public void setAccessible(boolean flag)
//將此對象的 accessible 標志設置為指示的布爾值。值為 true 則指示反射的對象在使用時應該取消 Java 語言訪問檢查。
//值為 false 則指示反射的對象應該實施 Java 語言訪問檢查。
Constructor cs5=c4.getDeclaredConstructor(String.class);
cs5.setAccessible(true);
Object obj2=cs5.newInstance("張三豐");
System.out.println(obj2);//Person [name=張三豐, age=0, address=null]
}
四、java.lang.reflect.Field
1、獲取Field對象
//獲取Class類的Field對象
public static void getFieldTest() throws Exception{
Class cs=Class.forName("com.linuxidc.org.base.relfect.Person");
//1、public Field[] getFields() throws SecurityException
//獲取Class 對象所表示的類或接口的所有可訪問公共(public修飾的)字段
Field [] fs=cs.getFields();
//2、public Field[] getDeclaredFields() throws SecurityException
// 獲取Class 對象所表示的類或接口所聲明的所有字段。包括公共、保護、默認(包)訪問和私有字段,但不包括繼承的字段
Field [] fs1=cs.getDeclaredFields();
//3、public Field getField(String name)throws NoSuchFieldException, SecurityException;
//獲取Class 對象所表示的類或接口的指定公共成員(public修飾)字段。name 參數是一個 String,用於指定所需字段的簡稱
Field fs2=cs.getField("address");
//public Field getDeclaredField(String name) throws NoSuchFieldException,SecurityException
//獲取 Class 對象所表示的類或接口的指定已聲明字段。name 參數是一個 String,它指定所需字段的簡稱
Field fs3=cs.getDeclaredField("name");
System.out.println(fs3);
}
2、通過Field對象對指定類屬性賦值
//使用 Field對象
public static void createVarValue() throws Exception{
Class cs=Class.forName("com.linuxidc.org.base.relfect.Person");
Object obj=cs.getConstructor().newInstance();
Field addressField=cs.getField("address");
//public void set(Object obj, Object value);
//將指定對象變量上此 Field 對象表示的字段設置為指定的新值。如果底層字段的類型為基本類型,則對新值進行自動解包
//obj - 應該修改其字段的對象 value - 正被修改的 obj 的字段的新值
addressField.set(obj, "北京");
System.out.println(obj); //Person [name=null, age=0, address=北京]
//對非public修飾的變量操作
Field nameField=cs.getDeclaredField("name");
//控制java的訪問檢查
nameField.setAccessible(true);
nameField.set(obj, "張三豐");
System.out.println(obj);//Person [name=張三豐, age=0, address=北京]
}
五、java.lang.reflect.Method
1、獲取Method對象
//獲取Method對象
public static void getMethodTest() throws Exception{
Class cs=Class.forName("com.linuxidc.org.base.relfect.Person");
//1、public Method[] getMethods() throws SecurityException
//獲取Class 對象所表示的類或接口(包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口)的公共 member 方法。
Method [] m1=cs.getMethods();
//2、public Method[] getDeclaredMethods() throws SecurityException
//獲取Class 對象表示的類或接口聲明的所有方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法
Method [] m2=cs.getDeclaredMethods();
//3、public Method getMethod(String name, Class<?>... parameterTypes)throws NoSuchMethodException, SecurityException;
// 獲取Class 對象所表示的類或接口的指定公共成員方法。name 參數是一個 String,用於指定所需方法的簡稱。parameterTypes 參數是按聲明順序標識該方法形參類型的 Class 對象的一個數組
Method m3=cs.getMethod("show");//無參的方法
Method m4=cs.getMethod("method",String.class);//帶參的方法
//public Method getDeclaredMethod(String name, Class<?>... parameterTypes)throws NoSuchMethodException,SecurityException
// Class 對象所表示的類或接口的指定已聲明方法。name 參數是一個 String,它指定所需方法的簡稱,parameterTypes 參數是 Class 對象的一個數組
Method m5=cs.getDeclaredMethod("function");//無參的方法
System.out.println(m5);
}
2、通過Method對象調用指定類的方法
// Method對象的使用
public static void createMethod() throws Exception{
Class cs=Class.forName("com.linuxidc.org.base.relfect.Person");
Object obj=cs.getConstructor().newInstance();
Method m3=cs.getMethod("show");//無參的方法
//public Object invoke(Object obj,Object... args)
//對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法 obj - 從中調用底層方法的對象 args - 用於方法調用的參數
m3.invoke(obj);
//對帶參方法的操作
Method m4=cs.getMethod("method",String.class);//帶參的方法
m4.invoke(obj,"北京");
//對有返回值得方法操作
Method m6=cs.getMethod("getString",String.class,int.class);//帶參的方法
Object str=m6.invoke(obj,"北京",200);
System.out.println(str);
//對私有無參方法的操作
Method m5=cs.getDeclaredMethod("function");
m5.setAccessible(true);
m5.invoke(obj);
}