如何使用 Java 反射?反射的用法及案例

简介

    Java Reflection,称为 Java 反射,是Java基础部分的一个比较难的点。Reflection(反射)是被视为动态语言的关键,通过反射机制,我们可以在运行时(runtime)获取类的完整结构。例如,可以获取到类的变量名、方法、构造器、内部类、接口、注解等等,并且通过反射机制可以对类内部进行操作。

    Java反射机制在实际开发中是非常常用的,强大一词完全可以用来形容它。作为Java基础内容的一部分,并且在很多开源框架(jdbc、spring、hibermate...)都使用到反射,可谓反射的重要性。

例子

首先,定义一个 Person 类及 Student 类,Student 继承自 Person 类,代码非常简单。如下:

    package com.test;
     
    public class Person<T> {
     
        public String weight;
        public String height;
     
        public Person() {
            super();
        }
     
        public Person(String weight, String height) {
            super();
            this.weight = weight;
            this.height = height;
        }
     
        public String getWeight() {
            return weight;
        }
     
        public void setWeight(String weight) {
            this.weight = weight;
        }
     
        public String getHeight() {
            return height;
        }
     
        public void setHeight(String height) {
            this.height = height;
        }
     
        @Override
        public String toString() {
            return "Person [weight=" + weight + ", height=" + height + "]";
        }
     
    }

    package com.test;
     
    import java.io.Serializable;
     
    public class Student extends Person<String> implements Serializable, Runnable {
     
        public String stuNo;
        private String stuName;
     
        public Student() {
            super();
        }
     
        public Student(String stuNo, String stuName) {
            super();
            this.stuNo = stuNo;
            this.stuName = stuName;
        }
     
        public String getStuNo() {
            return stuNo;
        }
     
        public void setStuNo(String stuNo) {
            this.stuNo = stuNo;
        }
     
        public String getStuName() {
            return stuName;
        }
     
        public void setStuName(String stuName) {
            this.stuName = stuName;
        }
     
        private int exam(String str, Integer tag) throws NoSuchMethodException {
            System.out.println(str);
            return tag;
        }
     
        @Override
        public String toString() {
            return "Student [stuNo=" + stuNo + ", stuName=" + stuName + "]";
        }
     
        @Override
        public void run() {
     
        }
    }

有了这两个类,我们就可以开始利用反射来获取类的内部结构了。我们常规的创建对象操作:

     
        @Test
        public void test() {
            Student student = new Student();
            student.setStuNo("01");
            student.setStuName("张三");
        }

    反射4种方式

在开始之前,我们来学习如何利用反射的方式来获取类的结构,反射的方式有这样 4 种。

    * 反射的4种获取方式,反射的源头就是获取到一个 Class 对象进行操作类的内部方法和获取类的结构。

      注意:父类中声明为 public 的变量、方法、接口等也可以被获取到。

        @Test
        public void test() throws Exception {
            /** 第一种反射方式 */
            Class clazz1 = new Student().getClass();
     
            /** 第二种反射方式 */
            Class clazz2 = Student.class;
     
            /** 第三种反射方式 */
            // 先声明 xxx 类所在包的完整名
            String className = "com.test.Student";
            Class clazz3 = Class.forName(className);
     
            /** 第四种反射方式 */
            Class clazz4 = this.getClass().getClassLoader().loadClass(className);
        }

以下都是利用反射来获取类结构的例子。

    获取类中的变量,并进行赋值

        @Test
        public void test() throws Exception {
            Class clazz = Student.class;
            Student student = (Student) clazz.newInstance();
            /** 声明为 public 类型的变量可以这样获取 **/
            Field field1 = clazz.getField("stuNo");
            field1.set(student, "01");
            System.out.println(student);
            /** 其他类型变量只能通过如下获取 **/
            Field field2 = clazz.getDeclaredField("stuName");
            field2.setAccessible(true);
            field2.set(student, "张三");
            System.out.println(student);
        }

    获取变量的权限修饰符(private、protected、public)

        @Test
        public void test() throws Exception {
            Class clazz = Student.class;
            Student student = (Student) clazz.newInstance();
            Field field1 = clazz.getField("stuNo");
            Field field2 = clazz.getDeclaredField("stuName");
        
            /** 获取 权限修饰符 **/
            String str = Modifier.toString(field1.getModifiers());
            System.out.println(str);
            String str2 = Modifier.toString(field2.getModifiers());
            System.out.println(str2);
        }

    获取类中的方法,并调用该方法(需注意权限修饰符)

    获取类中方法的返回值

    获取类中方法形参列表

    获取类中方法异常类型

        @Test
        public void test() throws Exception {
            Class clazz = Student.class;
            Student student = (Student) clazz.newInstance();
        
            Method method = clazz.getMethod("setStuNo", String.class);
            method.invoke(student, "02");
            System.out.println(student);
            /** 获取方法的返回值类型 */
            Class returnType = method.getReturnType();
            System.out.println(returnType);
     
            Method method2 = clazz.getDeclaredMethod("exam", String.class, Integer.class);
            method2.setAccessible(true);
            method2.invoke(student, "invoke exam method", 1);
            /** 获取方法的形参列表 */
            Class[] params = method2.getParameterTypes();
            for (Class param : params) {
                System.out.println(param);
            }
            /** 获取方法的异常类型 */
            Class[] exceptions =method2.getExceptionTypes();
            for(Class excp : exceptions) {
                System.out.println(excp);
            }
        }

    获取类的完整包名、

    类中所有的构造器、

    类中实现的所有接口

        @Test
        public void test() throws Exception {
            Class clazz = Student.class;
            Student student = (Student) clazz.newInstance();
            //获取包名
            System.out.println(clazz.getPackage());
            /**
             * 获取 所有构造器
             */
            Constructor[] constructor = clazz.getDeclaredConstructors();
            for(Constructor cons : constructor) {
                System.out.println(cons);
            }
            /**
             * 获取 所有接口
             */
            Class[] interfaces =clazz.getInterfaces();
            for( Class its:interfaces) {
                System.out.println(its);
            }
        }

    获取父类的结构

        @Test
        public void test() throws Exception {
            Class clazz = Student.class;
            Student student = (Student) clazz.newInstance();
            //获取父类
            System.out.println(clazz.getSuperclass());
            //获取带泛型的父类
            Type type = clazz.getGenericSuperclass();
            System.out.println(type);
            
            /**
             * 获取父类的泛型
             */
            Type type2 = clazz.getGenericSuperclass();
            ParameterizedType args = (ParameterizedType)type2;
            Type[] types = args.getActualTypeArguments();
            String t_Type = (String)types[0].getTypeName();
            System.out.println(t_Type);
        }

  以上的几个例子可以让我们知道反射的作用,反射能够在运行时状态下获取类的完整结构,在框架里显得尤为重要。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章