Java反射
反射機制的概念
反射是java的動态執行機制。反射機制是在運作狀态中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法和屬性;這種動态擷取的資訊以及動态調用對象的方法的功能稱為java語言的反射機制。
反射機制提供的功能
1、在運作時判斷任意一個對象所屬的類
2、在運作時構造任意一個類的對象
3、在運作時判斷任意一個類所具有的成員變量和方法
4、在運作時調用任意任意一個對象的方法
5、生成動态代理
反射機制的作用
1、反編譯:.class-->.java
2、通過反射機制通路java對象的屬性、方法、構造方法等
提供的反射機制的類
1、java.lang.class
2、java.lang.reflect.Field
3、java.lang.reflect.Constructor<T>
4、java.lang.reflect.Method
5、java.lang.reflect.Modifier
反射的方法、屬性等操作可以查詢API:
點選反射API連結:
https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/package-summary.html
首先看一個簡單示例,通過一個對象擷取完整的包名和類名:
package fanshe_test;
/**
* 通過一個對象獲得完整的包名和類名
* @author fandi
*
*/
public class Hello {
public static void main(String[] args){
Demo d = new Demo();
System.out.println(d.getClass().getName());
}
}
class Demo{
}
具體功能實作
反射機制擷取類的三種方法
Class<?> demo1 = null;
//第一種方式(建議采用第一種方式)
demo1 = Class.forName("fanshe_test2.Demo");
//第二種方式:java中每個類型都有class屬性
demo1 = Demo.class;
//第三種方式:java語言中任何一個java對象都有getClass方法,,這裡的demo1是運作時類
demo1 = new Demo().getClass();
示例:
package fanshe_test2;
/**
* 執行個體化Class類對象
* @author fandi
*
*/
public class Hello {
public static void main(String[] args){
Class<?> demo1 = null;
Class<?> demo2 = null;
Class<?> demo3 = null;
try {
//建議采用這種形式
demo1 = Class.forName("fanshe_test2.Demo");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
demo2 = new Demo().getClass();
demo3 = Demo.class;
System.out.println("類名稱" + demo1.getName());
System.out.println("類名稱" + demo2.getName());
System.out.println("類名稱" + demo3.getName());
}
}
class Demo{
}
建立對象
擷取類後需要建立它的對象,使用newInstance。
demo.newInstance();//調用Demo的無參構造方法
示例:
package fanshe_test3;
/**
* 通過Class執行個體化其他類的對象,通過無參構造執行個體化對象
* @author fandi
*
*/
public class Hello {
public static void main(String[] args){
Class<?> demo = null;
try {
demo = Class.forName("fanshe_test3.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Person per = null;
try {
per = (Person) demo.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
per.setAge(23);
per.setName("張三");
System.out.println(per);
}
}
class Person{
private String name;
private int age;
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;
}
@Override
public String toString() {
return "[name=" + this.name + ", age=" + this.age + "]";
}
}
注意:上面這個示例調用的無參構造函數,如果需要調用其它有參構造函數,則需要自己定義一個無參構造函數,否則會出現錯誤,學習下面的代碼。
示例:
package fanshe_test4;
import java.lang.reflect.Constructor;
public class Hello {
public static void main(String[] args){
Class<?> demo = null;
try {
demo = Class.forName("fanshe_test4.Person");
Person per1 = null;
Person per2 = null;
Person per3 = null;
Person per4 = null;
//取得全部的構造函數
Constructor<?> con[] = demo.getConstructors();
//判斷所擷取的構造函數的參數個數,以确定執行個體化的順序
for (int i = 0; i < con.length; i++) {
System.out.print(con[i].getParameterCount() + " ");
}
System.out.println();
//判斷所擷取的構造函數的參數類型,以确定執行個體化的順序
for (int j = 0; j < con.length; j++) {
Class<?> clazzs[] = con[j].getParameterTypes();
System.out.print("con[" + j + "](");
for (int k = 0; k < clazzs.length; k++) {
if (k == clazzs.length-1) {
System.out.print(clazzs[k].getName().toString());
} else {
System.out.print(clazzs[k].getName() + ",");
}
}
System.out.println(")");
}
per1 = (Person) con[0].newInstance((Object)"李四",23);
per2 = (Person) con[1].newInstance(24);
per3 = (Person) con[2].newInstance((Object)"張三");
per4 = (Person) con[3].newInstance();
// try {
// per1 = (Person) demo.newInstance();
// } catch (InstantiationException e) {
// e.printStackTrace();
// } catch (IllegalAccessException e) {
// e.printStackTrace();
// }
System.out.println(per1);
System.out.println(per2);
System.out.println(per3);
System.out.println(per4);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Person {
private String name;
private int age;
public Person(){
}
public Person(String name){
this.name = name;
}
public Person(int age){
this.age = age;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "[name=" + this.name + ", age=" + this.age + "]";
}
}
運作結果:
2 1 1 0
con[0](java.lang.String,int)
con[1](int)
con[2](java.lang.String)
con[3]()
[name=李四, age=23]
[name=null, age=24]
[name=張三, age=0]
[name=null, age=0]
擷取屬性
//擷取所有成員屬性
Field[] fs = demo.getDeclaredFields();
下面通過一個完整示例展示,示例:
package fanshe_test5;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* 擷取所有接口、擷取父類、擷取其他類的所有構造函數、擷取成員屬性
* @author fandi
*
*/
public class Hello{
public static void main(String[] args) {
Class<?> demo = null;
try {
demo = Class.forName("fanshe_test5.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//擷取所有接口
Class<?> inter[] = demo.getInterfaces();
for (int i = 0; i < inter.length; i++) {
System.out.println("實作的接口:" + inter[i].getName());
}
//擷取父類
Class<?> c = demo.getSuperclass();
System.out.println("繼承的父類:" + c.getName());
//擷取其他類的所有構造函數
Constructor<?>[] cons = demo.getConstructors();
for (int j = 0; j < cons.length; j++) {
System.out.println("其他類的構造函數:" + cons[j].getName());
System.out.println("其他類的構造函數:" + cons[j]);
}
//擷取所有成員屬性
Field[] fs = demo.getDeclaredFields();
//定義可變長的字元串,用來存儲屬性
StringBuffer sb = new StringBuffer();
//通過追加的方法,将每個屬性拼接到此字元串中
sb.append(Modifier.toString(demo.getModifiers()) + " class " + demo.getSimpleName() + "{\n");
for (Field field : fs) {
sb.append("\t");//空格
sb.append(Modifier.toString(field.getModifiers()) + " ");//獲得屬性的修飾符
sb.append(field.getType().getSimpleName() + " ");//擷取屬性類型的名字
sb.append(field.getName() + ";\n");//屬性的名字加回車
}
sb.append("}");
System.out.println(sb);
}
}
class Person implements China{
private String sex = "女";
public Person(){
}
public Person(String sex){
this.sex = sex;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public void sayChina() {
System.out.println("say China!!!");
}
@Override
public void sayHello(String name, int age) {
System.out.println("name:" + name + ", age:" + age);
}
}
interface China{
public static final String name = "張三";
public static int age = 20;
public void sayChina();
public void sayHello(String name, int age);
}
擷取方法
(詳見Method.invoke方法一節的講解)