• Java的反射


    程序可以访问、检测和修改它本身状态或行为的一种能力。

    反射在Java中的体现就是一组反射类Reflection API

    反射的入口—Class对象

    Class对象的获取方式

    1) Object.getClass()
    如果你有一个对象,那么可以调用这个对象的getClass()方法。

    Class c = "foo".getClass();
    
    Set<String> s = new HashSet<String>();
    Class c = s.getClass();
    
    • 1
    • 2
    • 3
    • 4

    2).class语法
    如果你有一个类,但是没有这个类的实例,那么可以用类名.class来获取。

    Class c = boolean.class; 
    Class c = int[][][].class;
    Class c = java.io.PrintStream.class;
    
    • 1
    • 2
    • 3

    包装类型用.TYPE

    Class c = Double.TYPE;
    
    • 1

    3)Class.forName()
    如果你有一个类的全路径,可以通过Class类的静态方法Class.forName()获取。

    Class c = Class.forName("com.duke.MyLocaleServiceProvider");
    
    • 1

    根据Class对象获取类修饰符和类型

    包括

    • 类名 c.getCanonicalName()
    • 类的修饰符 c.getModifiers()
    • 类的泛型参数 c.getTypeParameters()
    • 类的接口 c.getGenericInterfaces()
    • 类的父类 c.getSuperclass()
    • 类的注解 c.getAnnotations()

    待检测的类

    @MyAnnotation(value = "学生类")
    public class Student<T> extends People implements Serializable {
        private String name;
    
        public Student() {
        }
    
        public Student(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    // 父类
    public class People {
    }
    
    • 1
    • 2
    • 3
    // 自定义注解
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation {
        String value() default "";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    
    public class Demo {
        public static void main(String... args) {
            try {
                Class<?> c = Class.forName("lesson10.Student"); // 类路径
                System.out.format("类名 Class:%n  %s%n%n", c.getCanonicalName()); // 类名
                System.out.format("修饰符 Modifiers:%n  %s%n%n",
                        Modifier.toString(c.getModifiers())); // 修饰符
    
                System.out.format("泛型参数 Type Parameters:%n");// 泛型参数
                TypeVariable[] tv = c.getTypeParameters();
                if (tv.length != 0) {
                    System.out.format("  ");
                    for (TypeVariable t : tv)
                        System.out.format("%s ", t.getName());
                    System.out.format("%n%n");
                } else {
                    System.out.format("  -- No Type Parameters --%n%n");
                }
    
                System.out.format("接口 Implemented Interfaces:%n"); // 接口
                Type[] intfs = c.getGenericInterfaces();
                if (intfs.length != 0) {
                    for (Type intf : intfs)
                        System.out.format("  %s%n", intf.toString());
                    System.out.format("%n");
                } else {
                    System.out.format("  -- No Implemented Interfaces --%n%n");
                }
    
                System.out.format("继承路径 Inheritance Path:%n"); // 继承路径 父类->父类的父类...
                List<Class> l = new ArrayList<Class>();
                printAncestor(c, l);
                if (l.size() != 0) {
                    for (Class<?> cl : l)
                        System.out.format("  %s%n", cl.getCanonicalName());
                    System.out.format("%n");
                } else {
                    System.out.format("  -- No Super Classes --%n%n");
                }
    
                System.out.format("注解 Annotations:%n"); // 注解
                Annotation[] ann = c.getAnnotations();
                if (ann.length != 0) {
                    for (Annotation a : ann)
                        System.out.format("  %s%n", a.toString());
                    System.out.format("%n");
                } else {
                    System.out.format("  -- No Annotations --%n%n");
                }
    
            } catch (ClassNotFoundException x) {
                x.printStackTrace();
            }
        }
    
        private static void printAncestor(Class<?> c, List<Class> l) {
            Class<?> ancestor = c.getSuperclass();
            if (ancestor != null) {
                l.add(ancestor);
                printAncestor(ancestor, l);
            }
        }
    }
    
    # 运行结果
    类名 Class:
      lesson10.Student
    
    修饰符 Modifiers:
      public
    
    泛型参数 Type Parameters:
      T 
    
    接口 Implemented Interfaces:
      interface java.io.Serializable
    
    继承路径 Inheritance Path:
      lesson10.People
      java.lang.Object
    
    注解 Annotations:
      @lesson10.MyAnnotation(value=学生类)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84

    根据Class对象获取类的字段、方法、构造器。

    获取字段

    • getDeclaredField()
    • getField()
    • getDeclaredFields()
    • getFields()

    获取方法

    • getDeclaredMethod()
    • getMethod()
    • getDeclaredMethods()
    • getMethods()

    获取构造方法

    • getDeclaredConstructor()
    • getConstructor()
    • getDeclaredConstructors()
    • getConstructors()

    getDeclaredXxx() 可以获取privateprotected类型的字段/方法,但无法获取继承过来(父类)的字段/方法。

    getXxx() 可以获取继承过来(父类)的字段/方法,但是只能得到public类型的字段/方法,无法获取privateprotected类型的字段/方法。

    例如:

    方法返回类型是否获取父类字段是否获取私有字段
    getDeclaredField(name)Field×
    getField(name)Field×
    getDeclaredFields()Field[]x
    getFields()Field[]×

    部分实例代码:

    Class<?> c = Class.forName("lesson10.lesson1002.Student"); // 类路径
    Field[] declaredFields = c.getDeclaredFields();
    
    for (Field field : declaredFields) {
        System.out.println("declaredField:" + field.toGenericString());
    }
    
    Field[] fields = c.getFields();
    for (Field field : fields) {
        System.out.println("field:" + field.toGenericString());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    反射给字段赋值

    基本类型: field.setInt(object, val) field.setFloat(object, val)

    应用类型: field.set(object,otherObj)

    public class Student {
        public String name;
        public int age;
        private float height;
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", height=" + height +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    public class Demo {
        public static void main(String[] args) {
            try {
                Student s = new Student();
                Class<?> c = s.getClass();
    
                Field name = c.getDeclaredField("name");
                name.set(s, "小明");
    
                Field age = c.getDeclaredField("age");
                age.setInt(s, 18);
    
                Field height = c.getDeclaredField("height");
                //  height.setFloat(s, 180f);  // 错误 私有变量无法赋值
    
                System.out.println(s);
    
            } catch (NoSuchFieldException | IllegalAccessException x) {
                x.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    反射调用方法

    反射调用对象的方法格式如: method.invoke(object, param1, param2)

    public class Student {
        public String setName(String name, int age) {
            System.out.println("姓名:" + name);
            System.out.println("年龄:" + age);
            return "设置成功";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    public class Demo {
        public static void main(String[] args) {
            try {
                Student s = new Student();
                Class<?> c = s.getClass();
                Method method = c.getDeclaredMethod("setName", String.class, int.class);
                method.invoke(s, "小明", 18);
            } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    反射创建实例

    两种方式

    • 直接通过Class对象 class.newInstance()
    • 通过构造器类 Constructor constructor.newInstance();
    public class Student {
        private String name;
    
        public Student() {
        }
    
        public Student(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    public class Demo {
        public static void main(String[] args) {
            Class<?> c = Student.class;
            try {
                Student s1 = (Student) c.newInstance();
                System.out.println(s1);
    
                Constructor<?> ctor1 = c.getDeclaredConstructor();
                Student s2 = (Student) ctor1.newInstance();
                System.out.println(s2);
                
                // 传递参数
                Constructor<?> ctor2 = c.getDeclaredConstructor(String.class);
                Student s3 = (Student) ctor2.newInstance("张三");
                System.out.println(s3);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    结语

    反射机制非常重要,很多主流的框架都用到了反射。反射是高级程序员必须要掌握的,它的魅力无穷。

    关注微信公众号:小虎哥的技术博客,每天一篇文章,让你我都成为更好的自己

    在这里插入图片描述

  • 相关阅读:
    py20_(终于第 21 天)初识 Python 3 GUI 编程 tk 窗口之文本图像控件及面向对象 GUI 编程!
    阿里云服务器x86计算架构ECS实例规格汇总
    Scala (一) --------- Scala 入门
    年年出妖事,一例由JSON解析导致的"薛定谔BUG"排查过程记录
    腾讯云2023年双11云服务器优惠价格表
    MySQL数据库
    08 spark 集群搭建
    WebGL学习(一)渲染关系
    前端性能优化方法面试题回答思路总结
    ATF(TF-A) RSS-AP接口威胁模型-安全检测与评估
  • 原文地址:https://blog.csdn.net/qq_28883885/article/details/126060838