簡介
Java Reflection,稱爲 Java 反射,是Java基礎部分的一個比較難的點。Reflection(反射)是被視爲動態語言的關鍵,通過反射機制,我們可以在運行時(runtime)獲取類的完整結構。例如,可以獲取到類的變量名、方法、構造器、內部類、接口、註解等等,並且通過反射機制可以對類內部進行操作。
Java反射機制在實際開發中是非常常用的,強大一詞完全可以用來形容它。作爲Java基礎內容的一部分,並且在很多開源框架(jdbc、spring、hibermate...)都使用到反射,可謂反射的重要性。
例子
首先,定義一個 Person 類及 Student 類,Student 繼承自 Person 類,代碼非常簡單。如下:
package com.test;
public class Person<T> {
public String weight;
public String height;
public Person() {
super();
}
public Person(String weight, String height) {
super();
this.weight = weight;
this.height = height;
}
public String getWeight() {
return weight;
}
public void setWeight(String weight) {
this.weight = weight;
}
public String getHeight() {
return height;
}
public void setHeight(String height) {
this.height = height;
}
@Override
public String toString() {
return "Person [weight=" + weight + ", height=" + height + "]";
}
}
package com.test;
import java.io.Serializable;
public class Student extends Person<String> implements Serializable, Runnable {
public String stuNo;
private String stuName;
public Student() {
super();
}
public Student(String stuNo, String stuName) {
super();
this.stuNo = stuNo;
this.stuName = stuName;
}
public String getStuNo() {
return stuNo;
}
public void setStuNo(String stuNo) {
this.stuNo = stuNo;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
private int exam(String str, Integer tag) throws NoSuchMethodException {
System.out.println(str);
return tag;
}
@Override
public String toString() {
return "Student [stuNo=" + stuNo + ", stuName=" + stuName + "]";
}
@Override
public void run() {
}
}
有了這兩個類,我們就可以開始利用反射來獲取類的內部結構了。我們常規的創建對象操作:
@Test
public void test() {
Student student = new Student();
student.setStuNo("01");
student.setStuName("張三");
}
反射4種方式
在開始之前,我們來學習如何利用反射的方式來獲取類的結構,反射的方式有這樣 4 種。
* 反射的4種獲取方式,反射的源頭就是獲取到一個 Class 對象進行操作類的內部方法和獲取類的結構。
注意:父類中聲明爲 public 的變量、方法、接口等也可以被獲取到。
@Test
public void test() throws Exception {
/** 第一種反射方式 */
Class clazz1 = new Student().getClass();
/** 第二種反射方式 */
Class clazz2 = Student.class;
/** 第三種反射方式 */
// 先聲明 xxx 類所在包的完整名
String className = "com.test.Student";
Class clazz3 = Class.forName(className);
/** 第四種反射方式 */
Class clazz4 = this.getClass().getClassLoader().loadClass(className);
}
以下都是利用反射來獲取類結構的例子。
獲取類中的變量,並進行賦值
@Test
public void test() throws Exception {
Class clazz = Student.class;
Student student = (Student) clazz.newInstance();
/** 聲明爲 public 類型的變量可以這樣獲取 **/
Field field1 = clazz.getField("stuNo");
field1.set(student, "01");
System.out.println(student);
/** 其他類型變量只能通過如下獲取 **/
Field field2 = clazz.getDeclaredField("stuName");
field2.setAccessible(true);
field2.set(student, "張三");
System.out.println(student);
}
獲取變量的權限修飾符(private、protected、public)
@Test
public void test() throws Exception {
Class clazz = Student.class;
Student student = (Student) clazz.newInstance();
Field field1 = clazz.getField("stuNo");
Field field2 = clazz.getDeclaredField("stuName");
/** 獲取 權限修飾符 **/
String str = Modifier.toString(field1.getModifiers());
System.out.println(str);
String str2 = Modifier.toString(field2.getModifiers());
System.out.println(str2);
}
獲取類中的方法,並調用該方法(需注意權限修飾符)
獲取類中方法的返回值
獲取類中方法形參列表
獲取類中方法異常類型
@Test
public void test() throws Exception {
Class clazz = Student.class;
Student student = (Student) clazz.newInstance();
Method method = clazz.getMethod("setStuNo", String.class);
method.invoke(student, "02");
System.out.println(student);
/** 獲取方法的返回值類型 */
Class returnType = method.getReturnType();
System.out.println(returnType);
Method method2 = clazz.getDeclaredMethod("exam", String.class, Integer.class);
method2.setAccessible(true);
method2.invoke(student, "invoke exam method", 1);
/** 獲取方法的形參列表 */
Class[] params = method2.getParameterTypes();
for (Class param : params) {
System.out.println(param);
}
/** 獲取方法的異常類型 */
Class[] exceptions =method2.getExceptionTypes();
for(Class excp : exceptions) {
System.out.println(excp);
}
}
獲取類的完整包名、
類中所有的構造器、
類中實現的所有接口
@Test
public void test() throws Exception {
Class clazz = Student.class;
Student student = (Student) clazz.newInstance();
//獲取包名
System.out.println(clazz.getPackage());
/**
* 獲取 所有構造器
*/
Constructor[] constructor = clazz.getDeclaredConstructors();
for(Constructor cons : constructor) {
System.out.println(cons);
}
/**
* 獲取 所有接口
*/
Class[] interfaces =clazz.getInterfaces();
for( Class its:interfaces) {
System.out.println(its);
}
}
獲取父類的結構
@Test
public void test() throws Exception {
Class clazz = Student.class;
Student student = (Student) clazz.newInstance();
//獲取父類
System.out.println(clazz.getSuperclass());
//獲取帶泛型的父類
Type type = clazz.getGenericSuperclass();
System.out.println(type);
/**
* 獲取父類的泛型
*/
Type type2 = clazz.getGenericSuperclass();
ParameterizedType args = (ParameterizedType)type2;
Type[] types = args.getActualTypeArguments();
String t_Type = (String)types[0].getTypeName();
System.out.println(t_Type);
}
以上的幾個例子可以讓我們知道反射的作用,反射能夠在運行時狀態下獲取類的完整結構,在框架裏顯得尤爲重要。