Java工作笔记-对反射的进一步理解
目錄
?
?
基本概念
代碼與實例
?
基本概念
反射的進一步理解:
將類的各個組成部分封裝為其他對象(將一個類的組成部分封裝為其他對象)
就是反射。
?
Java代碼經歷的三個階段:
1. 寫好代碼.java后使用javac,編譯為字節碼文件:xxx.class
?? ?這個階段稱之為source源代碼階段。
3. 當程序要new一個對象時
?? ?這個階段稱之為Runtime運行時階段
2. 把字節碼文件.class加載進內存里面(使用類加載器ClassLoader)
在內存里面會存在一個對象用于描述字節碼文件。這個對象為Class對象。
所以java里面有個Class類。專門用來搞這個字節碼文件的
如:
成員變量(Fields)、構造方法(Constructor)、成員方法(Method)
這個階段稱之為Class類對象階段
?
第三階段都是同過第二階段創建起來的。第二個階段需要第一個階段。
?
反射好處:
? ? ? ? ? 1. 在程序運行過程中操作這些對象。(IDEA這個程序的 某個對象方法的提示,就是反射)
? ? ? ? ? 2. 可以解耦。提高程序可擴展性。
?
獲取Class對象的方式:
有3種方式,對應java代碼經歷的3個階段;
第一個階段只有.class字節碼文件,并沒有在內存中,要把.class加載到內存中生成對象。對應的API為:Class.forName("全類名") 返回class對象;
第二個階段:這個.class字節碼文件已經到內存了,這個時候,只要獲取他就可以了,類名.class,這種方式。
第三個階段:在Runtime時,已經有對象了,這個時候只要 對象.getClass()就可以了。這個getClass()類是在Object里面
的。
?
?
總結下:
? ? ? ? ? 1.Class.forName("全類名");將字節碼文件加載到內存,返回class對象。
? ? ? ? ? 2.類名.class;通過類名的屬性class獲取。
? ? ? ? ? 3.對象.getClass();getClass()方法在Object類中定義
?
?
?
?
代碼與實例
如下代碼:
Person.java
package Object;public class Person {private String name;private Integer age;public Person(String name, Integer age) {this.name = name;this.age = age;}public Person(){}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';} }Main1.java
import Object.Person;public class Main1 {public static void main(String[] args) throws ClassNotFoundException {//全類名Class cls1 = Class.forName("Object.Person");System.out.println(cls1);//類名.classClass cls2 = Person.class;System.out.println(cls2);//對象.getClass()Person p = new Person();Class cls3 = p.getClass();System.out.println(cls3);//比較下對象:System.out.println(cls1 == cls2);System.out.println(cls1 == cls3);} }程序運行截圖如下:
結論:
同一個字節碼文件.class在一次程序運行過程中,只會被加載一次,不論通過哪種方式獲取的class對象都是同一個。
第一種方式,多用于配置文件中,讀取文件,加載類
第二種方式,多用于參數的傳遞;
第三種方式,多用于對象的獲取字節碼
?
下面是
Class對象功能:
1.獲取成員變量;
? ? ? ? ? Field[] getFields()
? ? ? ? ? Field getField(String name)
? ? ? ? ? Field[] getDeclaredFields()
? ? ? ? ? Field getDeclaredField(String name)
2.獲取構造方法;
? ? ? ? ? Constructor<?>[] getConstructors()
? ? ? ? ? Constructor<T> getConstructor(類<?>... parameterTypes)
? ? ? ? ? Constructor<T> getDeclaredConstructor(類<?>... parameterTypes)
? ? ? ? ? Constructor<?>[] getDeclaredConstructors()
3.獲取成員方法;
? ? ? ? ? Method[] getMethods()
? ? ? ? ? Method[] getMethod(String name, 類<?>... parameterTypes)
? ? ? ? ? Method[] getDeclaredMethods()
? ? ? ? ? Method getDeclaredMethod(String name, 類<?>... parameterTypes)
4.獲取類名;
? ? ? ? ? String getName()
?
下面先給出變量名的實例
Person.java
package Object;public class Person {private String name;private Integer age;public String a;protected String b;String c;private String d;public Person(String name, Integer age) {this.name = name;this.age = age;}public Person(){}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", a='" + a + '\'' +", b='" + b + '\'' +", c='" + c + '\'' +", d='" + d + '\'' +'}';} }Main2.java
import Object.Person;import java.lang.reflect.Field;public class Main2 {public static void main(String[] args) throws Exception {//Field[] getFields()獲取所有public修飾的成員變量Class aClass = Class.forName("Object.Person");Field[] fields = aClass.getFields();for(Field field : fields){System.out.println(field);}//獲取及設置a的值Field a = aClass.getField("a");Person person = new Person();Object value = a.get(person);System.out.println("the a is : " + value);a.set(person, "你妹");System.out.println(person);System.out.println("----------華麗的分割線----------");//Field getDeclaredField(String name)Field[] declaredFields = aClass.getDeclaredFields();for(Field field : declaredFields){System.out.println(field);}//忽略修飾符暴力反射,設置值Field d = aClass.getDeclaredField("d");d.setAccessible(true);d.set(person, "豬小明");System.out.println(person);} }運行截圖如下:
下面是關于構造函數的反射:
Person還是與上面的一樣。
import Object.Person;import java.lang.reflect.Constructor;public class Main3 {public static void main(String[] args) throws Exception {Class personClass = Person.class;Constructor constructor = personClass.getConstructor(String.class, Integer.class);System.out.println(constructor);//創建對象Object p = constructor.newInstance("王二麻子", 99);System.out.println(p);System.out.println("----------華麗的分割線----------");Constructor constructor2 = personClass.getConstructor();Object p2 = constructor2.newInstance();System.out.println(p2);} }程序運行截圖如下:
下面是獲取成員方法的實例。
Person.java
package Object;public class Person {private String name;private Integer age;public String a;protected String b;String c;private String d;public Person(String name, Integer age) {this.name = name;this.age = age;}public Person(){}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", a='" + a + '\'' +", b='" + b + '\'' +", c='" + c + '\'' +", d='" + d + '\'' +'}';}public void eat(){System.out.println("eat... ...");}//帶參數的public void eat(String food){System.out.println("eat... ..." + food);} }Main4.java
import Object.Person;import java.lang.reflect.Method;public class Main4 {public static void main(String[] args) throws Exception {Class personClass = Person.class;//獲取指定名稱的方法Method eat = personClass.getMethod("eat");Person p = new Person();eat.invoke(p);System.out.println("----------華麗的風格線----------");Method eat1 = personClass.getMethod("eat", String.class);eat1.invoke(p, "西北風");//獲取所有Public修飾的方法Method[] methods = personClass.getMethods();for(Method method : methods){System.out.println(method);String name = method.getName();System.out.println(name);//method.setAccessible(true);}} }程序運行截圖如下:
下面是關于獲取類名的實例:
Main5.java
import Object.Person;public class Main5 {public static void main(String[] args){Class personClass = Person.class;System.out.println(personClass.getName());} }程序運行截圖如下:
import Object.Person;public class Main5 {public static void main(String[] args){Class personClass = Person.class;System.out.println(personClass.getName());} }程序運行截圖如下:
?
?
下面來仿一個案例,像Spring Boot那樣的通過配置application.properties既可以調用相應的類,和函數
這里應用到的就是反射
Main6.java
import Object.Person;import java.io.InputStream; import java.lang.reflect.Method; import java.util.Properties;public class Main6 {public static void main(String[] args) throws Exception {/**** 加載配置文件* 創建Properties對象* 加載配置文件,轉換為集合* 獲取class目錄下的配置文件*/Properties pro = new Properties();ClassLoader classLoader = Person.class.getClassLoader();InputStream resourceAsStream = classLoader.getResourceAsStream("application.properties");pro.load(resourceAsStream);//配置文件中定義的數據String className = pro.getProperty("className");String methodName = pro.getProperty("methodName");//加載該類到內存Class aClass = Class.forName(className);Object o = aClass.newInstance();//獲取方法并執行Method method = aClass.getMethod(methodName);method.invoke(o);} }通過這種配置文件,即可調用對應的類和方法:
程序運行截圖如下:
源碼打包下載地址:
https://github.com/fengfanchen/Java/tree/master/ReflectDemo
總結
以上是生活随笔為你收集整理的Java工作笔记-对反射的进一步理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 系统架构工作笔记-数据展示进程与读取数据
- 下一篇: 前端笔记-分享一个web后台登录及注册页