前言

记录一下反射相关内容,摘抄于此,方便自己查阅。

反射技术包括如下内容:

  1. 根据一个字符串得到一个类的对象

  2. 获取一个类的所有公用或私有、静态或实例的字段,方法,属性

  3. 对泛类型的反射

正文

本文介绍反射之获取类的构造函数以及其属性,方法。

在反射前,需要新增一个类用于测试,这创建一个Book类。

  1. package com.biumall.biutextview.book;
  2. public class Book {
  3.   //设置默认值
  4.   private String name = "笔友城堡";
  5.   private int page = 100;
  6.   //构造函数一:private修饰
  7.   private Book() {
  8.   }
  9.   //构造函数二:protected修饰
  10.   protected Book(String name){
  11.       this.name = name;
  12.   }
  13.   //构造函数三:public修饰
  14.   public Book(String name, int page) {
  15.       this.name = name;
  16.       this.page = page;
  17.   }
  18.   public String getName() {
  19.       return name;
  20.   }
  21.   public void setName(String name) {
  22.       this.name = name;
  23.   }
  24.   public int getPage() {
  25.       return page;
  26.   }
  27.   public void setPage(int page) {
  28.       this.page = page;
  29.   }
  30. }
复制

构造函数

getConstructors()只能获取Book类中public修饰的构造函数。

getConstructors()
  1. try {
  2.   //加载Book的Class
  3.   Class bookClass = Class.forName("com.biumall.biutextview.book.Book");
  4.   //查找所有public的构造函数
  5.   Constructor constructor[] = bookClass.getConstructors();
  6.   for (Constructor value : constructor) {
  7.       int mod = value.getModifiers();
  8.       //获取构造函数中的参数信息
  9.       Class[] parameterTypes = value.getParameterTypes();
  10.       Log.d(TAG, "invoke mod : " + Modifier.toString(mod) + " : " + parameterTypes.length);
  11.       for (Class parameterType : parameterTypes) {
  12.           //打印参数类型
  13.           Log.d(TAG, "invoke : " + parameterType.getName());
  14.       }
  15.   }
  16. } catch (Exception e) {
  17.   throw new RuntimeException(e);
  18. }
复制

输出结果

  1. # mod --> 构造函数修饰类型:构造函数参数个数
  2. # type --> 参数类型
  3. invoke mod : public : 2
  4. invoke type : java.lang.String
  5. invoke type : int
复制

也就只能获取到public修饰的构造函数

  1. public Book(String name, int page) {
  2.   this.name = name;
  3.   this.page = page;
  4. }
复制
getDeclaredConstructors()

可以获取所有的构造函数,包括private和protected修饰的。

把getConstructors()换成getDeclaredConstructors()即可,运行输出结果。

  1. # 构造函数一
  2. invoke mod : private : 0
  3. # 构造函数二
  4. invoke mod : public : 1
  5. invoke type : java.lang.String
  6. # 构造函数三
  7. invoke mod : public : 2
  8. invoke type : java.lang.String
  9. invoke type : int
复制
getDeclaredConstructor()

这个方法可以带参数和不带参数

不带参数

不带参数,就是获取无参数的构造函数

  1. try {
  2.   Class bookClass = Class.forName("com.biumall.biutextview.book.Book");
  3.   Constructor constructor = bookClass.getDeclaredConstructor();
  4.   Log.d(TAG, "invoke constructor : "+ constructor);
  5. } catch (ClassNotFoundException | NoSuchMethodException e) {
  6.   throw new RuntimeException(e);
  7. }
复制

输出结果

  1. invoke constructor : private com.biumall.biutextview.book.Book()
复制
带参数
  1. try {
  2.   Class bookClass = Class.forName("com.biumall.biutextview.book.Book");
  3. //指定参数类型
  4.   Class[] parameterTypes = {String.class};
  5. //查找指定参数类型的构造函数,如果没有对应的就会抛出异常
  6.   Constructor constructor = bookClass.getDeclaredConstructor(parameterTypes);
  7.   Log.d(TAG, "invoke constructor : " + constructor);
  8. } catch (ClassNotFoundException | NoSuchMethodException e) {
  9.   throw new RuntimeException(e);
  10. }
复制

Book类中存在参数类型为String的构造函数,所以可以查找到

  1. invoke constructor : protected com.biumall.biutextview.book.Book(java.lang.String)
复制

如果把parameterTypes中的String.class换成int.class,就会弹出异常:

  1. java.lang.NoSuchMethodException: <init> [int]
复制

上面只是查找一个参数的构造函数,现实中构造函数的参数可能存在多个。

下面举例查找public Book(String name, int page),只需要修改parameterTypes:

  1. Class[] parameterTypes = {String.class,int.class};
复制

输出结果

  1. invoke constructor : public com.biumall.biutextview.book.Book(java.lang.String,int)
复制

构造函数实例化

上面我们通过反射,可以获取类的构造函数,但,大多数时不仅要获取构造函数,还需要对其实例化。要得到类的实例,就需要借用Constructor的newInstance方法。

private构造函数

Book类中有个无参数的private修饰的构造函数,这么写是不让其他人调用,但如果一定要调用时这个构造函数时,就需要反射然后通过newInstance方法。

  1. try {
  2. Class bookClass = Class.forName("com.biumall.biutextview.book.Book");
  3. Constructor constructor = bookClass.getDeclaredConstructor();
  4. //private或protected必须要设置,public可以省略
  5. constructor.setAccessible(true);
  6. //通过newInstance()调用private Book()实例化
  7. Book book = (Book) constructor.newInstance();
  8. Log.d(TAG, "invoke name : "+ book.getName() + " , page :"+ book.getPage());
  9. } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException |
  10. IllegalAccessException | InstantiationException e) {
  11. throw new RuntimeException(e);
  12. }
复制

输出结果

  1. # Book类中特意写了默认值
  2. invoke name : 笔友城堡 , page :100
复制

也就是通过通过private Book()创建了一个Book对象。

protected构造函数
  1. public void invoke() {
  2. try {
  3. Class bookClass = Class.forName("com.biumall.biutextview.book.Book");
  4. Class[] parameterTypes = {String.class};
  5. Constructor constructor = bookClass.getDeclaredConstructor(parameterTypes);
  6. //private或protected必须要设置,public可以省略
  7. constructor.setAccessible(true);
  8. //通过newInstance()调用protected Book(String)实例化
  9. //传入String,初始化为[中国历史]
  10. Book book = (Book) constructor.newInstance("中国历史");
  11. Log.d(TAG, "invoke name : "+ book.getName() + " , page :"+ book.getPage());
  12. } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException |
  13. IllegalAccessException | InstantiationException e) {
  14. throw new RuntimeException(e);
  15. }
  16. }
复制

输出结果

  1. invoke name : 中国历史 , page :100
复制
public构造函数
  1. try {
  2. Class bookClass = Class.forName("com.biumall.biutextview.book.Book");
  3. Class[] parameterTypes = {String.class, int.class};
  4. Constructor constructor = bookClass.getDeclaredConstructor(parameterTypes);
  5. //通过newInstance()调用public Book(String name, int page)实例化
  6. //传入String和int,初始化为[中国历史, 5000]
  7. Book book = (Book) constructor.newInstance("中国历史", 5000);
  8. Log.d(TAG, "invoke name : " + book.getName() + " , page :" + book.getPage());
  9. } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException |
  10. IllegalAccessException | InstantiationException e) {
  11. Log.d(TAG, "invoke e : " + e);
  12. throw new RuntimeException(e);
  13. }
复制

输出结果

  1. invoke name : 中国历史 , page :5000
复制

属性

这个分静态属性和非静态属性。

  1. 改变静态属性是针对类来说;

  2. 改变非静态属性是针对某个对象来说,也就是对这个对象有效。

非静态属性

这里通过实例化私有的Book(),然后改变其对象中的name属性。

  1. try {
  2. Class bookClass = Class.forName("com.biumall.biutextview.book.Book");
  3. Constructor constructor = bookClass.getDeclaredConstructor();
  4. //private或protected必须要设置
  5. constructor.setAccessible(true);
  6. //通过newInstance()调用private Book()实例化
  7. Book book = (Book) constructor.newInstance();
  8. //获取Book中name属性
  9. Field field = bookClass.getDeclaredField("name");
  10. //private或protected必须要设置,public可以省略
  11. field.setAccessible(true);
  12. //传入需要获取的类对象,针对book对象
  13. Object nameObject = field.get(book);
  14. Log.d(TAG, "invoke 1 nameObject : "+ nameObject);
  15. //改变book对象的name的值
  16. field.set(book, "天下第一");
  17. Log.d(TAG, "invoke 2 nameObject : "+ book.getName());
  18. } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException |
  19. IllegalAccessException | InstantiationException | NoSuchFieldException e) {
  20. throw new RuntimeException(e);
  21. }
复制

输出结果

  1. invoke 1 nameObject : 笔友城堡
  2. invoke 2 nameObject : 天下第一
复制

book中的name的值被改变了。name是非静态属性,所以上面的修改也就是针对book这个对象来说。

静态属性

由于上面的Book类中没有静态属性,因此在之前的基础上新增一个company静态变量

  1. private static String company = "月球基地一号公司";
  2.  
  3. public static String getCompany(){
  4. return company;
  5. }
  6. public static void setCompany(String company){
  7. Book.company = company;
  8. }
复制

下面我们就获取company变量,然后改变其值。

  1. try {
  2. Log.d(TAG, "invoke 1 company : "+ Book.getCompany());
  3. Class bookClass = Class.forName("com.biumall.biutextview.book.Book");
  4. Field companyField = bookClass.getDeclaredField("company");
  5. //private或protected必须要设置,public可以省略
  6. companyField.setAccessible(true);
  7. //获取Book中company变量
  8. String company = (String) companyField.get(null);
  9. //改变companyObject的值
  10. companyField.set(company,"地球一号基地");
  11. Log.d(TAG, "invoke 2 company : "+ Book.getCompany());
  12. } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
  13. throw new RuntimeException(e);
  14. }
复制

输出结果

  1. invoke 1 company : 月球基地一号公司
  2. invoke 2 company : 地球一号基地
复制

也就是改变成功的。

方法

方法也分静态和非静态,这里也单独分开介绍。

  1. invoke静态方法是针对类来说;

  2. invoke非静态方法是针对某个对象来说,也就是对这个对象有效。

静态方法

静态方法中分为,带参数和不带参数。

无参数的方法
  1. try {
  2. Log.d(TAG, "invoke: ");
  3. Class bookClass = Class.forName("com.biumall.biutextview.book.Book");
  4. //获取getCompany方法
  5. Method getCompanyMethod = bookClass.getDeclaredMethod("getCompany");
  6. //private或protected必须要设置,public可以省略
  7. getCompanyMethod.setAccessible(true);
  8. //调用getCompany,无参函数,且静态的,第一个传入null
  9. String company = (String) getCompanyMethod.invoke(null);
  10. Log.d(TAG, "invoke company : " + company);
  11. } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException |
  12. IllegalAccessException e) {
  13. Log.d(TAG, "invoke e: "+ e);
  14. throw new RuntimeException(e);
  15. }
复制

输出结果

  1. invoke company : 月球基地一号公司
复制

打印的是默认值

有参数的方法
  1. try {
  2. Log.d(TAG, "invoke 1 company: "+ Book.getCompany());
  3. Class bookClass = Class.forName("com.biumall.biutextview.book.Book");
  4. //获取setCompany,有参数的,需要带上参数类型,这里只有一个
  5. Class[] parameterTypes = {String.class};
  6. Method setCompanyMethod = bookClass.getDeclaredMethod("setCompany", parameterTypes);
  7. //private或protected必须要设置,public可以省略
  8. setCompanyMethod.setAccessible(true);
  9. //参数列表,上面只有一个
  10. Object[] argList = {"太阳基地2号"};
  11. //调用setCompany方法,静态方法,第一个传入null,第二个写入参数列表
  12. setCompanyMethod.invoke(null, argList);
  13. Log.d(TAG, "invoke 1 company: "+ Book.getCompany());
  14. } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException |
  15. IllegalAccessException e) {
  16. Log.d(TAG, "invoke e: " + e);
  17. throw new RuntimeException(e);
  18. }
复制

结果

  1. invoke 1 company: 月球基地一号公司
  2. invoke 1 company: 太阳基地2
复制

第一个是默认值,第二个是我们调用setCompany()改变的值。

非静态方法

非静态方法也分为带参数无不带参数。

不带参数
  1. try {
  2. Class bookClass = Class.forName("com.biumall.biutextview.book.Book");
  3. Constructor constructor = bookClass.getDeclaredConstructor();
  4. //private或protected必须要设置,public可以省略
  5. constructor.setAccessible(true);
  6. //实例化对象,这里调用的是priave Book()
  7. Book book = (Book) constructor.newInstance();
  8. //获取getPage()的Method
  9. Method method = bookClass.getDeclaredMethod("getPage");
  10. //private或protected必须要设置,public可以省略
  11. //method.setAccessible(true);
  12. int page = (int) method.invoke(book);
  13. Log.d(TAG, "invoke page : "+ page);
  14. } catch (ClassNotFoundException | IllegalAccessException | InstantiationException |
  15. NoSuchMethodException | InvocationTargetException e) {
  16. throw new RuntimeException(e);
  17. }
复制

输出结果

  1. invoke page : 100
复制
带参数
  1. try {
  2. Class bookClass = Class.forName("com.biumall.biutextview.book.Book");
  3. Constructor constructor = bookClass.getDeclaredConstructor();
  4. constructor.setAccessible(true);
  5. Book book = (Book) constructor.newInstance();
  6. //获取setPage()的Method
  7. //setPage(int page)带一个int类型的参数
  8. Class[] parameterTypes = {int.class};
  9. Method method = bookClass.getDeclaredMethod("setPage", parameterTypes);
  10. //private或protected必须要设置,public可以省略
  11. //method.setAccessible(true);
  12. //带一个参数
  13. Object[] argsObject = {200};
  14. method.invoke(book, argsObject);
  15. Log.d(TAG, "invoke page : " + book.getPage());
  16. } catch (ClassNotFoundException | IllegalAccessException | InstantiationException |
  17. NoSuchMethodException | InvocationTargetException e) {
  18. throw new RuntimeException(e);
  19. }
复制

输出结果

  1. invoke page : 200
复制

参考文章

  1. Java基础之—反射2

相关文章

暂无评论

none
暂无评论...