「反射是框架設計的靈魂」,它能夠將類的各個組成部分封裝爲一個個的對象,經過 Java 的反射機制,程序員能夠更深刻地控制程序的運行過程。java
能夠在程序運行過程當中操做這些封裝的對象程序員
能夠解耦,提升程序的可擴展性api
public class Person { private String name; private Integer age; public String a; protected String b; String c; private String d; public Person() { } public Person(String name, Integer age) { this.name = name; this.age = age; } private void eat(String food){ System.out.println("吃" + food); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", a='" + a + '\'' + ", b='" + b + '\'' + ", c='" + c + '\'' + ", d='" + d + '\'' + '}'; } }
@Test public void test() throws ClassNotFoundException { //1. Class.forName("全類名"):將字節碼文件加入進內存,獲取Class對象 Class<?> clazz1 = Class.forName("com.sjl.Person"); System.out.println(clazz1); //2. 類名.class:經過類的屬性class獲取 Class<Person> clazz2 = Person.class; System.out.println(clazz2); //3. 類對象.getClass():經過Object中的方法getClass()獲取 Person person = new Person(); Class<? extends Person> clazz3 = person.getClass(); System.out.println(clazz3); //同一字節碼文件(*.class)在程序運行過程當中只被加載一次,因此不管哪一種方式得到的Class對象都是同一個 System.out.println(clazz1 == clazz2); //true System.out.println(clazz2 == clazz3); //true }
Class類的API,大體分爲一下幾類(參考jdk1.8 api)框架
@Test public void test1(){ //獲取Class對象 Class<Person> clazz = Person.class; //獲取類的全名稱 String name = clazz.getName(); System.out.println("類的全名稱:" + name); } @Test public void test2() throws Exception { //獲取Class對象 Class<?> clazz = Class.forName("com.sjl.Person"); //獲取Person的公有屬性列表 Field[] fields = clazz.getFields(); for(Field field : fields){ System.out.println("公共屬性:" + field); } //獲取指定的公有屬性 Field a = clazz.getField("a"); System.out.println("指定公共屬性a:" + a); System.out.println("================================"); //獲取Person的全部屬性列表,不論權限修飾符 Field[] declaredFields = clazz.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println("全部屬性:" + declaredField); } //獲取指定的屬性 Field d = clazz.getDeclaredField("d"); System.out.println("指定屬性d:" + d); System.out.println("================================"); //爲私有屬性 設置值 和 獲取值 Field name = clazz.getDeclaredField("name"); //暴力反射,忽略類的權限修飾符 name.setAccessible(true); //設值,須要傳一個person對象 Person person = new Person(); name.set(person, "張三"); //取值,也須要傳一個person對象 Object value = name.get(person); System.out.println(value); } @Test public void test3() throws Exception { //獲取Class對象 Class<?> clazz = Class.forName("com.sjl.Person"); //獲取公有構造方法 Constructor<?>[] constructors = clazz.getConstructors(); for (Constructor<?> constructor : constructors) { System.out.println(constructor); } //獲取空參構造器 Constructor<?> constructor1 = clazz.getConstructor(); //經過構造器建立對象 newInstance Object c1 = constructor1.newInstance(); System.out.println(c1); //若是是空參構造器還能夠簡寫,直接用Class對象建立 Object c2 = clazz.newInstance(); System.out.println(c2); } @Test public void test4() throws Exception { //獲取Class對象 Class<?> clazz = Class.forName("com.sjl.Person"); //獲取成員方法 Method eat_method = clazz.getDeclaredMethod("eat", String.class); //eat是私有方法,所以須要暴力反射 eat_method.setAccessible(true); //執行方法,傳入對象和參數 Person person = new Person(); eat_method.invoke(person, "火鍋"); }
實現:在不改變當前代碼的狀況下,建立任意一個類的實例並調用它的方法ide
思路:this
配置文件:設計
className=com.sjl.Person methodName=eat
Java代碼:code
public class ReflectDemo { //實現:在不改變當前代碼的狀況下,建立任意一個類的實例並調用它的方法 public static void main(String[] args) throws Exception { //獲取Class對象 Class<?> clazz = Class.forName(getValue("className")); //建立實例 Object o = clazz.newInstance(); //獲取方法對象 Method eat_method = clazz.getDeclaredMethod(getValue("methodName"), String.class); //執行 eat_method.setAccessible(true); eat_method.invoke(o, "火鍋"); } //根據key值讀取配置文件內容 public static String getValue(String key) throws IOException { Properties properties = new Properties(); InputStream is = ReflectDemo.class.getClassLoader().getResourceAsStream("config.properties"); properties.load(is); assert is != null; is.close(); return properties.getProperty(key); } }
運行結果:對象
吃火鍋
新建一個類Person2,將eat方法的輸出稍做修改,將配置文件修改成內存
className=com.sjl.Person2 methodName=eat
運行結果
吃火鍋,我是二號選手