Java讓咱們在識別對象和類的信息,主要有兩種方式:一種是傳統的RTTI,它假定咱們在編譯時已經知道了全部的類型信息;另外一種是反射機制,它容許咱們在運行時發現和使用類的信息。java
使用反射賦予了Java動態編譯的能力,不然類的元數據信息只能經過靜態編譯的方式實現。緩存
靜態編譯:在編譯時肯定類型,綁定對象即經過ide
動態編譯:運行時肯定類型,綁定對象。動態編譯最大限度地發揮了Java的靈活性,體現了多態的應用,能夠下降類之間的耦合性。this
反射就是在運行時才知道要操做的類是什麼,而且能夠在運行時獲取類的完整構造,並調用對應的方法。對象
反射是被視爲動態語言的關鍵,反射機制容許程序在執行期間藉助Reflection API取得任何類的內部信息,並能直接操做任意對象的內部屬性和方法。內存
在運行時判斷任意一個對象所屬的類get
在運行的時候構造任意一個類的對象it
在運行時判斷任意一個類所具備的成員變量和方法io
在運行時調用任意一個對象的成員變量和方法編譯
public class Person {
public String name;
private int age;
public int id;
public Person() {
}
public Person(String name, int age) {
super();
this.name = name;
this.age = 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 "Person [name=" + name + ", age=" + age + "]";
}
public void show(){
System.out.println("我是人類");
}
public void display(String nation){
System.out.println("個人家鄉:"+nation);
}
public static void info(){
System.out.println("元宵節快樂!");
}
}
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.junit.Test;
public class TestField {
// 獲取對應運行時類的屬性
@Test
public void test1(){
Class clazz = Person.class;
// 1.getFields():只能獲取運行時類中及其父類聲明爲public的屬性
Field[] fields = clazz.getFields();
for (int i = 0; i < fields.length; i++) {
System.out.println(fields[i].getName());
}
//2.getDeclaredFields():獲取運行時類自己聲明的全部屬性
Field[] fields2 = clazz.getDeclaredFields();
for (Field f : fields2) {
System.out.println(f.getName());
}
}
// 獲取權限修飾符 變量類型 屬性名
@Test
public void test2(){
Class clazz = Person.class;
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
// 1.獲取每一個屬性的訪問修飾符
int i = f.getModifiers();
System.out.println(Modifier.toString(i)+" ");
// 2.獲取屬性的類型
Class type = f.getType();
System.out.println(type.getName()+" ");
// 3.獲取屬性名
System.out.println(f.getName()+" ");
System.out.println();
}
}
// 調用運行時類中指定的屬性
@Test
public void test3() throws Exception{
Class clazz = Person.class;
// 1.獲取指定的屬性
// getField(String fieldName):獲取運行時類中聲明爲public的屬性名
Field name = clazz.getField("name");
// 2.建立運行時類的對象
Person p = (Person) clazz.newInstance();
System.out.println(p);
// 3.將運行時類的屬性賦值
name.set(p, "jack");
System.out.println(p);
// 4.getDeclaredField(String fieldName):獲取運行時類中指定的名爲fieldName的屬性
Field age = clazz.getDeclaredField("age");
// 因爲屬性權限修飾符的限制,爲了保證能夠爲屬性賦值,須要在操做前使得此屬性能夠被操做。
age.setAccessible(true);
age.set(p, 20);
System.out.println(p);
}
}
import java.lang.reflect.Constructor;
import org.junit.Test;
public class TestConstructor {
@Test
public void test1() throws Exception{
// 建立對應運行時類的對象使用newInstance()其實是調用了運行時類的空參構造器
// 要求:1.對應的運行時類要有空參的構造器 2.構造器的權限修飾符權限要足夠
String className = "com.hpe.reflect.Person";
Class clazz = Class.forName(className);
Person p = (Person) clazz.newInstance();
System.out.println(p);
}
// 獲取Person類中全部的構造器
@Test
public void test2() throws Exception{
Class clazz = Class.forName("com.hpe.reflect.Person");
Constructor[] cons = clazz.getDeclaredConstructors();
for (Constructor c : cons) {
System.out.println(c);
}
}
// 調用指定的構造器
@Test
public void test3() throws Exception{
Class clazz = Class.forName("com.hpe.reflect.Person");
Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
cons.setAccessible(true);
Person p = (Person) cons.newInstance("張三",20);
System.out.println(p);
}
}
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.junit.Test;
public class TestMethod {
// 調用運行時類中指定的方法
@Test
public void test1() throws Exception{
Class clazz = Person.class;
// getMethod(String methodName,class... params):獲取運行時類中聲明爲public的方法
Method m1 = clazz.getMethod("show");
Person p = (Person) clazz.newInstance();
// 調用指定的方法Object invoke(Object obj,Object... obj)
Object returnVal = m1.invoke(p);
System.out.println(returnVal);
// 帶有返回值類型的方法
Method m2 = clazz.getMethod("toString");
// 設置屬性值
Field name = clazz.getField("name");
name.set(p, "lim");
Object returnVal2 = m2.invoke(p);
System.out.println(returnVal2);
// 調用靜態方法
Method m3 = clazz.getMethod("info");
m3.invoke(Person.class);
// getDeclaredMethod(String methodName,class...param):獲取運行時類聲明的指定方法
Method m4 = clazz.getDeclaredMethod("display", String.class);
m4.setAccessible(true);
m4.invoke(p, "CHN");
}
}
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.junit.Test;
public class TestReflection { // 經過傳統方式調用對象 調用其方法 @Test public void test1(){ Person p = new Person(); p.setAge(15); p.setName("jack"); System.out.println(p); p.show(); p.display("山東"); } // 有了反射,能夠經過反射建立一個類的對象,並調用其中的結構 @Test public void test2() throws Exception{ Class clazz = Person.class; // 1.建立clazz對應運行時類Person類的對象 Person p = (Person)clazz.newInstance(); System.out.println(p); // 二、經過反射調用運行時類指定的屬性 Field f1 = clazz.getField("name"); // 設置某個對象的屬性值 f1.set(p, "jack"); System.out.println(p); Field f2 = clazz.getDeclaredField("age"); // 設置容許訪問 f2.setAccessible(true); f2.set(p, 20); System.out.println(p); // 3.經過反射調用運行時類指定的方法 Method m1 = clazz.getMethod("show"); // 調用方法 m1.invoke(p); Method m2 = clazz.getMethod("display", String.class); m2.invoke(p, "China"); } /* * java.lang.Class:反射的源 * 建立一個類,經過編譯(javac.exe)生成對應的class文件,以後咱們經過java.exe(JVM類加載器)加載此class文件 * 到內存,就是一個運行時類,存放在緩存區。Class clazz = Person.class * 1.每一個運行時類只加載一次 * 2.有了Class實例後,能夠執行: * ①.建立對應運行時類的對象(重點) * ②.獲取對應運行時類的完整結構(屬性、方法、構造器、內部類、父類、包、異常、註解) * ③.調用對應的運行時類的指定結構(屬性、方法、構造器)(重點) */ @Test public void test3(){ Person p = new Person(); // 調用其getClass()方法返回運行時類 Class clazz = p.getClass();// Person.class System.out.println(clazz); } @Test public void test4() throws ClassNotFoundException{ // 1.調用類自己的.class屬性 Class clazz1 = Person.class; System.out.println(clazz1.getName()); Class clazz2 = String.class; System.out.println(clazz2.getName()); // 2.經過類的對象獲取 Person p = new Person(); Class clazz3 = p.getClass(); System.out.println(clazz3.getName()); // 3.經過Class類的靜態方法獲取 String className = "com.hpe.reflect.Person"; Class clazz4 = Class.forName(className); System.out.println(clazz4.getName()); // 4.經過類的加載器(瞭解) ClassLoader classLoader = this.getClass().getClassLoader(); Class clazz5 = classLoader.loadClass(className); System.out.println(clazz5.getName()); }}