目录
前言
反射技术包括如下内容:
-
根据一个字符串得到一个类的对象
-
获取一个类的所有公用或私有、静态或实例的字段,方法,属性
-
对泛类型的反射
正文
本文介绍反射之获取类的构造函数以及其属性,方法。
在反射前,需要新增一个类用于测试,这创建一个Book类。
package com.biumall.biutextview.book; public class Book { //设置默认值 private String name = "笔友城堡"; private int page = 100; //构造函数一:private修饰 private Book() { } //构造函数二:protected修饰 protected Book(String name){ this.name = name; } //构造函数三:public修饰 public Book(String name, int page) { this.name = name; this.page = page; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPage() { return page; } public void setPage(int page) { this.page = page; } }
构造函数
getConstructors()只能获取Book类中public修饰的构造函数。
getConstructors()
try { //加载Book的Class Class bookClass = Class.forName("com.biumall.biutextview.book.Book"); //查找所有public的构造函数 Constructor constructor[] = bookClass.getConstructors(); for (Constructor value : constructor) { int mod = value.getModifiers(); //获取构造函数中的参数信息 Class[] parameterTypes = value.getParameterTypes(); Log.d(TAG, "invoke mod : " + Modifier.toString(mod) + " : " + parameterTypes.length); for (Class parameterType : parameterTypes) { //打印参数类型 Log.d(TAG, "invoke : " + parameterType.getName()); } } } catch (Exception e) { throw new RuntimeException(e); }
输出结果
# mod --> 构造函数修饰类型:构造函数参数个数 # type --> 参数类型 invoke mod : public : 2 invoke type : java.lang.String invoke type : int
也就只能获取到public修饰的构造函数
public Book(String name, int page) { this.name = name; this.page = page; }
getDeclaredConstructors()
可以获取所有的构造函数,包括private和protected修饰的。
把getConstructors()换成getDeclaredConstructors()即可,运行输出结果。
# 构造函数一 invoke mod : private : 0 # 构造函数二 invoke mod : public : 1 invoke type : java.lang.String # 构造函数三 invoke mod : public : 2 invoke type : java.lang.String invoke type : int
getDeclaredConstructor()
这个方法可以带参数和不带参数
不带参数
不带参数,就是获取无参数的构造函数
try { Class bookClass = Class.forName("com.biumall.biutextview.book.Book"); Constructor constructor = bookClass.getDeclaredConstructor(); Log.d(TAG, "invoke constructor : "+ constructor); } catch (ClassNotFoundException | NoSuchMethodException e) { throw new RuntimeException(e); }
输出结果
invoke constructor : private com.biumall.biutextview.book.Book()
带参数
try { Class bookClass = Class.forName("com.biumall.biutextview.book.Book"); //指定参数类型 Class[] parameterTypes = {String.class}; //查找指定参数类型的构造函数,如果没有对应的就会抛出异常 Constructor constructor = bookClass.getDeclaredConstructor(parameterTypes); Log.d(TAG, "invoke constructor : " + constructor); } catch (ClassNotFoundException | NoSuchMethodException e) { throw new RuntimeException(e); }
Book类中存在参数类型为String的构造函数,所以可以查找到
invoke constructor : protected com.biumall.biutextview.book.Book(java.lang.String)
如果把parameterTypes中的String.class换成int.class,就会弹出异常:
java.lang.NoSuchMethodException: <init> [int]
上面只是查找一个参数的构造函数,现实中构造函数的参数可能存在多个。
下面举例查找public Book(String name, int page),只需要修改parameterTypes:
Class[] parameterTypes = {String.class,int.class};
输出结果
invoke constructor : public com.biumall.biutextview.book.Book(java.lang.String,int)
构造函数实例化
上面我们通过反射,可以获取类的构造函数,但,大多数时不仅要获取构造函数,还需要对其实例化。要得到类的实例,就需要借用Constructor的newInstance方法。
private构造函数
Book类中有个无参数的private修饰的构造函数,这么写是不让其他人调用,但如果一定要调用时这个构造函数时,就需要反射然后通过newInstance方法。
try { Class bookClass = Class.forName("com.biumall.biutextview.book.Book"); Constructor constructor = bookClass.getDeclaredConstructor(); //private或protected必须要设置,public可以省略 constructor.setAccessible(true); //通过newInstance()调用private Book()实例化 Book book = (Book) constructor.newInstance(); Log.d(TAG, "invoke name : "+ book.getName() + " , page :"+ book.getPage()); } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException | InstantiationException e) { throw new RuntimeException(e); }
输出结果
# Book类中特意写了默认值 invoke name : 笔友城堡 , page :100
也就是通过通过private Book()创建了一个Book对象。
protected构造函数
public void invoke() { try { Class bookClass = Class.forName("com.biumall.biutextview.book.Book"); Class[] parameterTypes = {String.class}; Constructor constructor = bookClass.getDeclaredConstructor(parameterTypes); //private或protected必须要设置,public可以省略 constructor.setAccessible(true); //通过newInstance()调用protected Book(String)实例化 //传入String,初始化为[中国历史] Book book = (Book) constructor.newInstance("中国历史"); Log.d(TAG, "invoke name : "+ book.getName() + " , page :"+ book.getPage()); } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException | InstantiationException e) { throw new RuntimeException(e); } }
输出结果
invoke name : 中国历史 , page :100
public构造函数
try { Class bookClass = Class.forName("com.biumall.biutextview.book.Book"); Class[] parameterTypes = {String.class, int.class}; Constructor constructor = bookClass.getDeclaredConstructor(parameterTypes); //通过newInstance()调用public Book(String name, int page)实例化 //传入String和int,初始化为[中国历史, 5000] Book book = (Book) constructor.newInstance("中国历史", 5000); Log.d(TAG, "invoke name : " + book.getName() + " , page :" + book.getPage()); } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException | InstantiationException e) { Log.d(TAG, "invoke e : " + e); throw new RuntimeException(e); }
输出结果
invoke name : 中国历史 , page :5000
属性
这个分静态属性和非静态属性。
-
改变静态属性是针对类来说;
-
改变非静态属性是针对某个对象来说,也就是对这个对象有效。
非静态属性
这里通过实例化私有的Book(),然后改变其对象中的name属性。
try { Class bookClass = Class.forName("com.biumall.biutextview.book.Book"); Constructor constructor = bookClass.getDeclaredConstructor(); //private或protected必须要设置 constructor.setAccessible(true); //通过newInstance()调用private Book()实例化 Book book = (Book) constructor.newInstance(); //获取Book中name属性 Field field = bookClass.getDeclaredField("name"); //private或protected必须要设置,public可以省略 field.setAccessible(true); //传入需要获取的类对象,针对book对象 Object nameObject = field.get(book); Log.d(TAG, "invoke 1 nameObject : "+ nameObject); //改变book对象的name的值 field.set(book, "天下第一"); Log.d(TAG, "invoke 2 nameObject : "+ book.getName()); } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException | InstantiationException | NoSuchFieldException e) { throw new RuntimeException(e); }
输出结果
invoke 1 nameObject : 笔友城堡 invoke 2 nameObject : 天下第一
book中的name的值被改变了。name是非静态属性,所以上面的修改也就是针对book这个对象来说。
静态属性
由于上面的Book类中没有静态属性,因此在之前的基础上新增一个company静态变量
private static String company = "月球基地一号公司"; public static String getCompany(){ return company; } public static void setCompany(String company){ Book.company = company; }
下面我们就获取company变量,然后改变其值。
try { Log.d(TAG, "invoke 1 company : "+ Book.getCompany()); Class bookClass = Class.forName("com.biumall.biutextview.book.Book"); Field companyField = bookClass.getDeclaredField("company"); //private或protected必须要设置,public可以省略 companyField.setAccessible(true); //获取Book中company变量 String company = (String) companyField.get(null); //改变companyObject的值 companyField.set(company,"地球一号基地"); Log.d(TAG, "invoke 2 company : "+ Book.getCompany()); } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) { throw new RuntimeException(e); }
输出结果
invoke 1 company : 月球基地一号公司 invoke 2 company : 地球一号基地
也就是改变成功的。
方法
方法也分静态和非静态,这里也单独分开介绍。
-
invoke静态方法是针对类来说;
-
invoke非静态方法是针对某个对象来说,也就是对这个对象有效。
静态方法
静态方法中分为,带参数和不带参数。
无参数的方法
try { Log.d(TAG, "invoke: "); Class bookClass = Class.forName("com.biumall.biutextview.book.Book"); //获取getCompany方法 Method getCompanyMethod = bookClass.getDeclaredMethod("getCompany"); //private或protected必须要设置,public可以省略 getCompanyMethod.setAccessible(true); //调用getCompany,无参函数,且静态的,第一个传入null String company = (String) getCompanyMethod.invoke(null); Log.d(TAG, "invoke company : " + company); } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { Log.d(TAG, "invoke e: "+ e); throw new RuntimeException(e); }
输出结果
invoke company : 月球基地一号公司
打印的是默认值
有参数的方法
try { Log.d(TAG, "invoke 1 company: "+ Book.getCompany()); Class bookClass = Class.forName("com.biumall.biutextview.book.Book"); //获取setCompany,有参数的,需要带上参数类型,这里只有一个 Class[] parameterTypes = {String.class}; Method setCompanyMethod = bookClass.getDeclaredMethod("setCompany", parameterTypes); //private或protected必须要设置,public可以省略 setCompanyMethod.setAccessible(true); //参数列表,上面只有一个 Object[] argList = {"太阳基地2号"}; //调用setCompany方法,静态方法,第一个传入null,第二个写入参数列表 setCompanyMethod.invoke(null, argList); Log.d(TAG, "invoke 1 company: "+ Book.getCompany()); } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { Log.d(TAG, "invoke e: " + e); throw new RuntimeException(e); }
结果
invoke 1 company: 月球基地一号公司 invoke 1 company: 太阳基地2号
第一个是默认值,第二个是我们调用setCompany()改变的值。
非静态方法
非静态方法也分为带参数无不带参数。
不带参数
try { Class bookClass = Class.forName("com.biumall.biutextview.book.Book"); Constructor constructor = bookClass.getDeclaredConstructor(); //private或protected必须要设置,public可以省略 constructor.setAccessible(true); //实例化对象,这里调用的是priave Book() Book book = (Book) constructor.newInstance(); //获取getPage()的Method Method method = bookClass.getDeclaredMethod("getPage"); //private或protected必须要设置,public可以省略 //method.setAccessible(true); int page = (int) method.invoke(book); Log.d(TAG, "invoke page : "+ page); } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) { throw new RuntimeException(e); }
输出结果
invoke page : 100
带参数
try { Class bookClass = Class.forName("com.biumall.biutextview.book.Book"); Constructor constructor = bookClass.getDeclaredConstructor(); constructor.setAccessible(true); Book book = (Book) constructor.newInstance(); //获取setPage()的Method //setPage(int page)带一个int类型的参数 Class[] parameterTypes = {int.class}; Method method = bookClass.getDeclaredMethod("setPage", parameterTypes); //private或protected必须要设置,public可以省略 //method.setAccessible(true); //带一个参数 Object[] argsObject = {200}; method.invoke(book, argsObject); Log.d(TAG, "invoke page : " + book.getPage()); } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) { throw new RuntimeException(e); }
输出结果
invoke page : 200
参考文章
-
《