Java中反射机制入门
目錄
3.反射類java.lang.Class
5.反射屬性java.lang.reflect.Field
7.反射方法java.lang.reflect.Method
8.反射構造方法java.lang.reflect.Constructor
1.反射機制的作用:通過java語言中的反射機制可以直接操作字節碼文件(讀、改),直接操作代碼片段class文件,注意字節碼文件都是保存在方法區的,只有一個。
? ?反射機制所在的包:java.lang.reflect.*
? ?反射機制的相關重要類:
? ? ? ? ①java.lang.Class:代表字節碼文件,即一個類型,整個類。
? ? ? ? ②java.lang.reflect.Method:代表字節碼中的方法字節碼,即類中的方法。
? ? ? ? ③java.lang.reflect.Constructor:代表字節碼中的構造方法字節碼,即類中的構造方法。
? ? ? ? ④java.lang.reflect.Field:代表字節碼中的屬性字節碼,即類中的成員變量。
2.要操作一個類的字節碼,需要首先獲取到這個類的字節碼,獲取java.lang.Class實例的三種方式:
? ? ? ? ①static Class forName(String className):返回與帶有給定字符串名的類或接口相關聯的
? ? ? ? ? Class對象。其中字符串需要的是一個完整類名,完整類名必須帶有包名。
? ? ? ? ②java中任何一個對象都有一個方法getClass()--->引用.getClass();
? ? ? ? ③java語言中任何一種類型,包括基本數據類型,都有.class屬性。
3.反射類java.lang.Class
? ?通過反射機制,獲取到Class,可以通過Class來實例化對象。方法newInstance(),會調用類的無參數構造方法來完成對象的創建,因此還是必須要在類中寫一個無參構造函數。
? ? ? ? 引用.newInstance();
? ?將反射機制與IO、properties文件、Properties集合結合起來使用,使創建對象時更靈活。如果想改變創建的對象,代碼不需要改動,可以修改配置文件,配置文件修改之后,可以創建出不同的實例對象。符合OCP開閉原則,對擴展開放,對修改關閉。
? ? ? ? 目前這段代碼的文件路徑是相對路徑,可能只在IDEA中可以使用(IDEA中默認的當前路徑是
??????project的根),因此不具有通用性,移植性差,可以通過代碼獲取絕對路徑進行修改。
? ? ? ? 以下的修改的前提是文件必須在類路徑下,凡是在src下的都是類路徑下。src是類的根路徑
? ? ? (其實真正的是out文件夾下的class文件)。通過以下代碼可以拿到該文件的絕對路徑。
? ? ? ? 而這種方法可以直接返回一個流,在聯合使用使可以寫得更簡單。
? ? ? ? 在java.util包下提供了一個資源綁定器,便于獲取屬性配置文件中的內容,使用這種方式的時
? ? ? 候,屬性配置文件xxx.properties必須放到類路徑下。使用該方法就不再需要IO流+Properties集
??????合的方式,變得又更簡單了。以后用的也都是這種方式。注意只有后綴為properties的文件可以
??????使用這種方式。
4.Class.forName()方法在執行時,會導致類加載,因此會讓類中的靜態代碼塊執行(類加載的時候)。
5.反射屬性java.lang.reflect.Field
/* 反射屬性Field Field發明以為字段,其實就是屬性/成員*/ public class Student {//4個Field分別采用了不同的訪問控制權限修飾符public int no;//Field對象private String name;//Field對象protected int age;boolean sex;public static final double MATH_PI = 3.1415926; } import java.lang.reflect.Field; import java.lang.reflect.Modifier;/* 反射Student類當中所有的Field*/ public class ReflectTest {public static void main(String[] args) throws Exception {//獲取整個類Class studentClass = Class.forName("Student");String className = studentClass.getName();System.out.println(className);//完整類名(會顯示出包的名字,但我這里沒設置包)String simpleName = studentClass.getSimpleName();System.out.println(simpleName);//簡類名//獲取類中所有public修飾的FieldField[] fields = studentClass.getFields();System.out.println(fields.length);//輸出為1,測試數組中只有1個元素//取出這個FieldField f = fields[0];//取出這個Field的名字String name = f.getName();System.out.println(name);//"no"System.out.println("============");//獲取所有的FieldField[] fs = studentClass.getDeclaredFields();System.out.println(fs.length);//4//遍歷for(Field field : fs){//獲取屬性的修飾符列表int i = field.getModifiers();//返回的修飾符是一個數字,每個數字是修飾符的代號System.out.println(i);//可以將這個“代號”數字轉換成“字符串”String modifierString = Modifier.toString(i);System.out.println(modifierString);//獲取屬性的類型System.out.println(field.getType().getName());//獲取屬性的名字System.out.println(field.getName());}} }? ?反編譯一個類的屬性:
import java.lang.reflect.Field; import java.lang.reflect.Modifier;/* 通過反射機制,反編譯一個類的屬性Field*/ public class ReflectTest02 {public static void main(String[] args) throws Exception{//創建這個是為了拼接字符串StringBuilder s = new StringBuilder();Class studentClass = Class.forName("java.lang.String");s.append(Modifier.toString(studentClass.getModifiers()) +"class"+ studentClass.getSimpleName() +" {\n");Field[] fields = studentClass.getDeclaredFields();for(Field field : fields){s.append("\t");s.append(Modifier.toString(field.getModifiers()));s.append(" ");s.append(field.getType().getSimpleName());s.append(" ");s.append(field.getName());s.append(";\n");}s.append('}');System.out.println(s);} }? ?通過反射機制去訪問對象的屬性:
import java.lang.reflect.Field;/* 必須掌握:怎么通過反射機制訪問一個java對象的屬性?給屬性賦值set獲取屬性的值get*/ public class ReflectTest03 {public static void main(String[] args) throws Exception{Class studentClass = Class.forName("Student");Object obj = studentClass.newInstance();//obj就是Student對象。(底層調用無參構造方法)//獲取no屬性(屬性和屬性之間靠名字來區分,根據屬性的名稱來獲取Field)Field noField = studentClass.getDeclaredField("no");//以后可以把屬性名字寫到配置文件里//給obj對象(Student對象)的no屬性賦值noField.set(obj,2222);//給obj對象的no屬性賦值2222//讀取屬性的值System.out.println(noField.get(obj));//可以訪問私有的屬性嗎?不可以 // Field nameField = studentClass.getDeclaredField("name"); // nameField.set(obj,"zhangsan"); // System.out.println(nameField.get(obj));//怎么訪問私有的屬性?打破封裝Field nameField = studentClass.getDeclaredField("name");//打破封裝nameField.setAccessible(true);//設置完后就可以訪問私有屬性了nameField.set(obj,"zhangsan");System.out.println(nameField.get(obj));} }6.可變長參數。
? ?語法:類型...? ? (注意:一定是三個點)
? ?可變長參數要求的參數個數是0~N個。
? ?可變長參數在參數列表中必須在最后一個位置上,而且可變長度參數只能有一個。
? ?可變長參數可以當作一個數組來看待。
public class ArgsTest {public static void main(String[] args) {ArgsTest.m();ArgsTest.m(10);ArgsTest.m(10,20);//參數長度可變,但是類型要一樣//類型不對就出錯//ArgsTest.m("abc");ArgsTest.m2(10,"abc","def");ArgsTest.m3("abc","de","f");String[] strs = {"a","b","c","d"};//也可以傳一個數組m3(strs);m3(new String[]{"我","是","中","國","人"});}public static void m(int... args){System.out.println("m方法執行了");}public static void m2(int a,String... args){System.out.println("m2方法執行了");}public static void m3(String... args){//args有length屬性,說明args是一個數組//可以將可變長度參數當作一個數組來看for(int i = 0;i < args.length;i++){System.out.println(args[i]);}} }7.反射方法java.lang.reflect.Method
public class UserService {//登錄方法//true表示登錄成功,false表示登陸失敗public boolean login(String name,String password){if("admin".equals(name) && "123".equals(password)){return true;}return false;}//退出系統方法public void logout(){System.out.println("系統已經安全退出");} } import java.lang.reflect.Method; import java.lang.reflect.Modifier;/* 作為了解內容:反射Method。*/ public class ReflectTest01 {public static void main(String[] args) throws Exception{//獲取類Class userServiceClass = Class.forName("UserService");//獲取所有的Method(包括私有的)Method[] methods = userServiceClass.getDeclaredMethods();System.out.println(methods.length);//2//遍歷for(Method method : methods){//獲取修飾符列表System.out.println(Modifier.toString(method.getModifiers()));//獲取返回值類型System.out.println(method.getReturnType().getSimpleName());//獲取方法名System.out.println(method.getName());//方法的參數列表(一個方法的參數可能會有多個)Class[] parameterTypes = method.getParameterTypes();for(Class parameterType : parameterTypes){System.out.println(parameterType.getSimpleName());}}} }? ?反編譯Method
import java.lang.reflect.Method; import java.lang.reflect.Modifier;/* 了解一下,不需要掌握:反編譯Method,目前反編譯不出里面的方法體。*/ public class ReflectTest02 {public static void main(String[] args) throws Exception {StringBuilder s = new StringBuilder();Class userServiceClass = Class.forName("UserService");s.append(Modifier.toString(userServiceClass.getModifiers()) + "class" + userServiceClass.getSimpleName() + "{\n");Method[] methods = userServiceClass.getDeclaredMethods();for(Method method : methods){s.append("\t");s.append(Modifier.toString(method.getModifiers()));s.append(" ");s.append(method.getReturnType().getSimpleName());s.append(" ");s.append(method.getName());s.append("(");Class[] classes = method.getParameterTypes();for(Class parameterType : classes){s.append(parameterType.getSimpleName());s.append(",");}//刪除指定下標上的字符s.deleteCharAt(s.length()-1);s.append("){}\n");}s.append("}");System.out.println(s);} }? ?反編譯機制調用方法。
import java.lang.reflect.Method;/* 重點:必須掌握,通過反射機制怎么調用一個對象的方法。*/ public class ReflectTest03 {public static void main(String[] args) throws Exception{//不使用反射機制UserService userService1 = new UserService();boolean loginSuccess = userService1.login("admin","123");System.out.println(loginSuccess);//使用反射機制來調用一個對象的方法Class userServiceClass = Class.forName("UserService");//創建對象Object obj = userServiceClass.newInstance();//獲取Method,因為存在方法重載,所以也需要加入形參類型來識別是哪個方法Method loginMethod = userServiceClass.getDeclaredMethod("login",String.class,String.class);//Method loginMethod = userServiceClass.getDeclaredMethod("login",int.class);//調用方法//反射機制中最重要的方法,必須記住Object retValue = loginMethod.invoke(obj,"admin","123");System.out.println(retValue);} }? ?反射機制就是讓代碼很具有通用性,可變化的內容都寫到配置方法當中,將來修改配置文件之后,創建的對象不一樣了,調用的方法也不同了,但是java代碼不需要做任何改動。
8.反射構造方法java.lang.reflect.Constructor
public class Vip {int no;String name;String birth;boolean sex;public Vip() {}public Vip(int no, String name) {this.no = no;this.name = name;}public Vip(int no, String name, String birth) {this.no = no;this.name = name;this.birth = birth;}public Vip(int no, String name, String birth, boolean sex) {this.no = no;this.name = name;this.birth = birth;this.sex = sex;}@Overridepublic String toString() {return "Vip{" +"no=" + no +", name='" + name + '\'' +", birth='" + birth + '\'' +", sex=" + sex +'}';} }? ?反編譯Contructor
import java.lang.reflect.Constructor; import java.lang.reflect.Modifier;/* 反編譯一個類的Constructor構造方法。*/ public class ReflectTest {public static void main(String[] args) throws Exception{StringBuilder s = new StringBuilder();Class vipClass = Class.forName("Vip");s.append(Modifier.toString(vipClass.getModifiers()) + " class " + vipClass.getSimpleName() + "{\n");//拼接構造方法Constructor[] constructors = vipClass.getConstructors();for(Constructor constructor : constructors){s.append("\t");s.append(Modifier.toString(constructor.getModifiers()));s.append(" ");s.append(vipClass.getSimpleName());s.append("(");Class[] parameterTypes = constructor.getParameterTypes();for(Class parameterType : parameterTypes){s.append(parameterType.getSimpleName());s.append(",");}if(parameterTypes.length > 0){s.deleteCharAt(s.length() - 1);}s.append("){}\n");}s.append("}");System.out.println(s);} }? ?利用反射機制調用構造方法
import java.lang.reflect.Constructor;/* 利用反射機制構造方法創建對象*/ public class ReflectTest02 {public static void main(String[] args) throws Exception{//不使用反射機制創建對象Vip v1 = new Vip();Vip v2 = new Vip(110,"zhangsan","2020-10-11",true);//使用反射機制創建對象Class c = Class.forName("Vip");//調用無參數構造方法Object obj = c.newInstance();System.out.println(obj);//調用有參數構造方法//第一步:先獲取這個有參數的構造方法Constructor con = c.getDeclaredConstructor(int.class,String.class,String.class,boolean.class);//第二步:調用構造方法new對象Object newObj = con.newInstance(110,"xxy","1998-09-10",true);System.out.println(newObj);} }9.獲取一個類的父類及實現的接口。? ?
PS:根據動力節點課程整理,如有侵權,聯系刪除。
總結
以上是生活随笔為你收集整理的Java中反射机制入门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springBoot-Quartz 定时
- 下一篇: Android so 文件全部报错:Du