• Java程序设计——反射(Java高级应用)


    目录

    ​编辑

    1.Executable抽象类

    2.Constructor类

    3.Method类

    4.Field类

    5.Parameter类


    Java中的许多对象在运行时都有两种类型:

    • 编译时类型
    • 运行时类型

    在程序运行时获取对象的真实信息有以下两种做法:

    • 在知道对象的具体类型的情况下,可以先使用instanceof运算符进行判断,再使用强制类型转换将其转化成运行时的类型变量即可
    • 在无法预知该对象是属于哪些类的情况下,必须通过反射来发现该对象和类的真实信息

    反射机制允许程序运行时借助Reflection API取得任何类的内部信息,并能直接操作对象的内部属性和方法

    Reflection API提供了Constructor、Field和Method类,分别用于描述类的构造方法、属性和方法

    Java反射机制的功能:

    • 在运行时判断任意一个对象所属的类
    • 在运行时构造任意一个类的对象
    • 在运行时获取任意一个类的成员变量和方法
    • 在运行时调用任意一个对象的方法
    • 生成动态代理

    如:获取类对象的所有方法

    1. import java.lang.reflect.Method;
    2. public class Demo {
    3. public static void main(String[] args) throws ClassNotFoundException {
    4. Class cs = Class.forName("java.lang.String"); // 获取String类的Class对象
    5. Method[] methods = cs.getDeclaredMethods(); // 获取当前类对象的所有方法
    6. for (Method method: methods
    7. ) {
    8. System.out.println(method);
    9. }
    10. }
    11. }

    1.Executable抽象类

    Executable抽象类派生出了Constructor和Method两个子类,其提供了大量方法来获取参数、修饰符或注解等信息

    方法功能
    Parameter[ ]  getParameters()获取所有形参,返回一个数组 
    int getParameterCount()获取形参个数
    abstract int getModifiers()获取修饰符,返回的整数是修饰符public、protected、private、final、static、abstract等关键字所对应的常量
    boolean isVarArgs()判断是否包含数量可变的形参

    2.Constructor类

    Constructor类用于表示类的构造方法,通过调用Class对象的getConstructors()方法可以获取当前类的构造方法的集合

    方法功能
    String getName()返回构造方法的名称
    Class[ ] getParameterTypes()返回当前构造方法的参数类型
    int getModifiers()获取修饰符的整形标识,返回的整数是修饰符public、protected、private、final、static、abstract等关键字所对应的常量,需要使用Modifier工具类的方法解码后才能获得真实的修饰符
    1. package reflect;
    2. import java.lang.reflect.Constructor;
    3. import java.lang.reflect.Modifier;
    4. public class ConstructorDemo {
    5. public static void main(String[] args) throws ClassNotFoundException {
    6. // 1.获取String类的对象
    7. Class cs = Class.forName("java.lang.String");
    8. // 2.返回所有构造方法
    9. Constructor[] constructors = cs.getConstructors();
    10. // 3.遍历所有构造方法
    11. for (Constructor constructor : constructors) {
    12. // 4.输出构造方法的名称
    13. String constructorName = constructor.getName();
    14. System.out.println(constructorName+"()");
    15. // 5.获取构造方法修饰符的整型标识
    16. int mod = constructor.getModifiers();
    17. // 6.使用Modifier工具类的方法输出真实的修饰符
    18. String modifier = Modifier.toString(mod);
    19. System.out.println(modifier);
    20. // 7.获取构造方法的参数类型
    21. Class[] paraTypes = constructor.getParameterTypes();
    22. // 8.输出构造方法的参数类型名称
    23. for (Class cas : paraTypes) {
    24. System.out.print(cas.getName() + " ");
    25. }
    26. System.out.println("\n------------------------");
    27. }
    28. }
    29. }


    3.Method类

    Method类用于封装方法的信息,调用Class对象的getMethods()方法或getMethod()可以获取当前类的所有方法或指定方法

    方法功能
    String getName()返回方法的名称
    Class[ ]  getParameterTypes()返回当前方法的参数类型
    int getModifiers()返回修饰符的整形标识
    Class getReturnType()返回当前方法的返回类型
    1. package reflect;
    2. import java.lang.reflect.Method;
    3. import java.lang.reflect.Modifier;
    4. public class MethodDemo {
    5. public static void main(String[] args) throws ClassNotFoundException {
    6. // 1.获取String类的对象
    7. Class cs = Class.forName("java.lang.String");
    8. // 2.返回所有方法
    9. Method[] methods = cs.getMethods();
    10. // 3.遍历所有方法
    11. for (Method method : methods) {
    12. // 4.输出方法的名称
    13. String methodName = method.getName();
    14. System.out.println(methodName+"()");
    15. // 5.获取方法修饰符的整型标识
    16. int mod = method.getModifiers();
    17. // 6.使用Modifier工具类的方法输出真实的修饰符
    18. String modifier = Modifier.toString(mod);
    19. System.out.println(modifier);
    20. // 7.获取方法的参数类型
    21. Class[] paraTypes = method.getParameterTypes();
    22. // 8.输出方法的参数类型名称
    23. for (Class cas : paraTypes) {
    24. System.out.print(cas.getName() + " ");
    25. }
    26. System.out.println("\n------------------------");
    27. }
    28. }
    29. }


    4.Field类

    Field类用于封装属性的信息,调用Class对象的getFields()或getField()方法可以获取当前类的所有属性或指定属性

    方法功能
    String getName()返回属性的名称
    int getModifiers()返回修饰符的整型标识
    getXxx(Object obj)获取属性的值,此处Xxx对应Java8中的基本类型,如果属性是引用类型,直接使用get(Object obj)方法
    setXxx(Object obj,Xxx val)设置属性的值,此处Xxx对应Java8中的基本类型,如果属性是引用类型,直接使用set(Object obj,Object val)方法
    Class[ ] getType()返回当前属性的类型
    1. package reflect;
    2. import java.lang.reflect.Field;
    3. import java.lang.reflect.Modifier;
    4. class Student{
    5. private String name;
    6. protected int age;
    7. public String toString(){
    8. return ("姓名:" + name + "---" + "年龄:" + age);
    9. }
    10. }
    11. public class FieldDemo {
    12. public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
    13. // 1.获取Student类对应的Class对象
    14. Class studentClass = Student.class;
    15. // 2.返回所有属性(不包括超类属性)
    16. Field[] fields = studentClass.getDeclaredFields();
    17. // 3.遍历所有属性
    18. for (Field field : fields) {
    19. // 4.输出属性的类型
    20. Class fieldType = field.getType();
    21. System.out.println(fieldType);
    22. // 5.获取属性的修饰符
    23. int mod = field.getModifiers();
    24. // 6.使用Modifier工具类输出修饰符对应的常量
    25. String val = Modifier.toString(mod);
    26. System.out.println(val);
    27. // 7.输出属性的名称
    28. String fieldName = field.getName();
    29. System.out.println(fieldName);
    30. System.out.println("----------------");
    31. }
    32. // 1.创建一个Student对象
    33. Student student = new Student();
    34. // 2.获取Student类的属性对象
    35. // getDeclaredField:获取各种访问控制符的成员变量
    36. Field nameField = studentClass.getDeclaredField("name");
    37. Field ageField = studentClass.getDeclaredField("age");
    38. // 3.设置通过 反射 访问该类成员变量时取消访问权限检查
    39. nameField.setAccessible(true);
    40. ageField.setAccessible(true);
    41. // 4.获取Student类Class对象对应的实例
    42. Object obj = studentClass.newInstance();
    43. // 5.获取Student类的属性对象的值
    44. String name = (String) nameField.get(obj);
    45. int age = ageField.getInt(obj);
    46. System.out.println("Student类属性对象的值:" + name + ":" + age);
    47. // 6.设置Student类的属性对象的值
    48. nameField.set(student,"lisi");
    49. ageField.setInt(student,18);
    50. // 7.输出对象student的信息(默认调用toString()方法)
    51. System.out.println(student);
    52. }
    53. }


    5.Parameter类

    每个Parameter对象代表方法的一个参数,调用Class对象getParameters()可以获取当前方法的所有参数,Parameter类中提供许多方法获取参数信息

    方法功能
    int getModifiers()返回参数的修饰符的整型标识
    String getNmae()返回参数的形参名
    Type getParameterizedType()获取带泛型的形参类型
    Class<?>  getType()获取形参类型
    boolean isVarArgs()判断该参数是否是可变参数
    boolean isNamePresent()判断.class文件中是否包含方法的形参名信息
    1. package reflect;
    2. import java.lang.reflect.Method;
    3. import java.lang.reflect.Parameter;
    4. class MethodParameter{
    5. public void test1(String str){
    6. }
    7. public void test2(int val, boolean bool){
    8. }
    9. }
    10. public class ParameterDemo {
    11. public static void main(String[] args) {
    12. // 1.获取MethodParameter类的Class对象
    13. Class cls = MethodParameter.class;
    14. // 2.获取MethodParameter类的所有方法
    15. Method[] methods = cls.getMethods();
    16. // 3.遍历MethodParameter类的所有方法
    17. for (Method method : methods) {
    18. // 4.输出该方法名
    19. String methodName = method.getName();
    20. System.out.println("方法名:" + methodName);
    21. // 5.输出该方法的形参个数
    22. int count = method.getParameterCount();
    23. System.out.println("形参个数:" + count);
    24. // 6.获取该方法的所有参数
    25. Parameter[] parameters = method.getParameters();
    26. // 7.遍历该方法的所有参数
    27. for (Parameter parameter : parameters) {
    28. // 8.输出参数名
    29. System.out.println("参数名:" + parameter.getName());
    30. // 9.输出形参类型
    31. System.out.println("形参类型:" + parameter.getType());
    32. // 10.输出泛型类型
    33. System.out.println("泛型类型:" + parameter.getParameterizedType());
    34. System.out.println("——————————————————————————————");
    35. }
    36. }
    37. }
    38. }

    使用javac命令编译java源文件时,默认生成的.class文件不包含方法形参名信息,所以调用getName()不能得到正确的形参名

    如果希望javac命令编译java源文件时保留形参信息,则需要为编译命令指定-parameters选项


  • 相关阅读:
    使用cpolar内网穿透实现远程Stackedit Markdown编辑器
    查找组成一个偶数最接近的两个素数
    Java 同步锁ReentrantLock与抽象同步队列AQS
    腾讯云轻量应用服务器三年租用价格表_免去续费困扰
    RHCSA的一些简单操作命令
    win10取消ie浏览器自动跳转edge浏览器
    Nginx基于Basic Auth实现静态资源的访问权限控制
    短视频矩阵系统源码(搭建)
    Ubuntu18.04安装docker及nvidia docker、NVIDIA Container Toolkit
    【每日一题】补档 ARC134D - Concatenate Subsequences | 思维 | 简单
  • 原文地址:https://blog.csdn.net/Mr_Morgans/article/details/125529332