Java反射的理解和使用

反射的定义

定义:反射就是对封装类的字段,方法和构造函数的所有信息进行编程访问的一种手段。

(Java的反射(reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任
意一个对象,都能够调用它的任意方法和属性,既然能拿到那么,我们就可以修改部分类型信息;这种动态获取信
息以及动态调用对象方法的功能称为java语言的反射(reflection)机制。)

 一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象 来提供给用户进行操作。

相关知识

Class对象

在java世界里,一切皆对象。从某种意义上来说,java有两种对象:实例对象和Class对象。每个类的运行时的类型信息就是用Class对象表示的。它包含了与类有关的信息。其实我们的实例对象就通过Class对象来创建的。(这个类Class对象只有一个,这个类的所有实例对象都通过对象头指向这个Class对象)

(Class类被创建后的对象就是Class对象,这里需要注意,Class对象表示的是自己手动编写类的类型信息。)

具体过程如下

各种信息对象

 

反射的使用

步骤:

获取Class对象

将Class对象里的信息对象解剖出来

调用

准备一个类用来做例子:

package 反射.myreflect1;

public class Student {
    public String name = "66"; // 公有字段,存储学生的姓名,初始值为 "66"
    protected int age = 11; // 受保护字段,存储学生的年龄,初始值为 11
    private String sex = "男"; // 私有字段,存储学生的性别,初始值为 "男"

    // 默认构造方法
    public Student() {
        System.out.println("调用了无参构造");
    }

    // 使用指定的姓名初始化
    public Student(String name) {
        this.name = name;
        System.out.println("调用了一个参数的构造");
    }

    // 使用指定的姓名和年龄初始化
    protected Student(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("调用了两个参数的构造");
    }

    // 使用指定的姓名、年龄和性别初始化
    private Student(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        System.out.println("调用了三个参数的构造");
    }

    // 公有方法,打印 "public"
    public void Print1(String body) {
        System.out.println("public"+body);
    }

    // 私有方法,打印 "private"
    private void Print2(String body) {
        System.out.println("private"+body);
    }

    // 受保护方法,打印 "protected"
    protected void Print3(String body) {
        System.out.println("protected"+body);
    }

    // 重写的 toString 方法,返回表示学生对象的字符串
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}

获取Class对象的三种方式

第一种,使用 Class.forName("类的全路径名"); 静态方法。
        前提:已明确类的全路径名。
第二种,使用 .class 方法。
        说明:仅适合在编译前就已经明确要操作的 Class
第三种,使用类对象的 getClass() 方法

例子:

 获取对象的代码演示

public class MyReflectDemo1 {
    /*
     * 获取class对象的三种方式:
     *   1. Class.forName("全类名");
     *   2. 类名.class
     *   3. 对象.getClass();
     *
     * */
    public static void main(String[] args) throws ClassNotFoundException {
        //1. 第一种方式
        //全类名 : 包名 + 类名
        //最为常用的
        Class clazz1 = Class.forName("反射.myreflect1.Student");

        //2. 第二种方式
        //一般更多的是当做参数进行传递
        Class clazz2 = Student.class;

       //3.第三种方式
        //当我们已经有了这个类的对象时,才可以使用。
        Student s = new Student();
        Class clazz3 = s.getClass();

        //说明我们通过不同的方式获取到的都是同一个Class对象
        System.out.println(clazz1.equals(clazz2));
        System.out.println(clazz2.equals(clazz3));

        说明实例对象都是公用一个Class对象的
        System.out.println("说明实例对象都是公用一个Class对象的----------------------------------------");
        Student s1 = new Student();
        Student s2 = new Student();
        Class clazz11 = s1.getClass();
        Class clazz22 = s2.getClass();
        System.out.println(clazz11.equals(clazz22));
    }
}

结果:

 说明我们通过不同的方式获取到的都是同一个Class对象

通过反射获取构造方法并调用

package 反射.myreflect1;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;

public class MyReflectDemo {
    /*
        Class类中用于获取构造方法的方法
            Constructor<?>[] getConstructors()                                返回所有公共构造方法对象的数组
            Constructor<?>[] getDeclaredConstructors()                        返回所有构造方法对象的数组
            Constructor<T> getConstructor(Class<?>... parameterTypes)         返回单个公共构造方法对象
            Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回单个构造方法对象

        Constructor类中用于创建对象的方法
            T newInstance(Object... initargs)                                 根据指定的构造方法创建对象
            setAccessible(boolean flag)                                       设置为true,表示取消访问检查
    */
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1.获取class字节码文件对象
        Class clazz = Class.forName("反射.myreflect1.Student");

       System.out.println("获取公共构造方法对象---------------------------------------------------------");

       Constructor[] cons1 = clazz.getConstructors();
        for (Constructor con : cons1) {
            System.out.println(con);
        }

        System.out.println();
        System.out.println("获取全部构造方法对象(包括:私有、受保护、默认、公有)---------------------------------------------------------");
        System.out.println();
        Constructor[] cons2 = clazz.getDeclaredConstructors();
        for (Constructor con : cons2) {
            System.out.println(con);
        }

        System.out.println();
        System.out.println("根据参数获取单个构造方法对象(包括:私有、受保护、默认、公有)---------------------------------------------------------");
        Constructor con4 = clazz.getDeclaredConstructor(String.class,int.class,String.class);
        System.out.println(con4);

        //获取对应参数列表
        Parameter[] parameters = con4.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }

        System.out.println();
        System.out.println("创建实例---------------------------------------------------------");
        //暴力反射:表示临时取消权限校验
        con4.setAccessible(true);
        //创建对象
        反射.myreflect1.Student stu = (Student) con4.newInstance("张三",23,"男");

        System.out.println(stu);


    }
}

结果

通过反射获取成员变量并设置

 

package 反射.myreflect1;
import 反射.myreflect1.Student;
import java.lang.reflect.Field;

public class MyReflectDemo2 {
    /*
           Class类中用于获取成员变量的方法
                Field[] getFields():                返回所有公共成员变量对象的数组
                Field[] getDeclaredFields():        返回所有成员变量对象的数组
                Field getField(String name):        返回单个公共成员变量对象
                Field getDeclaredField(String name):返回单个成员变量对象

           Field类中用于赋值对象的方法
                void set(Object obj, Object value):赋值
                Object get(Object obj)              获取值

        */
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        //1.获取class字节码文件的对象
        Class clazz = Class.forName("反射.myreflect1.Student");

        //2.获取所有的成员变量
        System.out.println();
        System.out.println("获取所有的成员变量-----------------------------------------------------------");
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        //获取单个的成员变量
        System.out.println();
        System.out.println("获取单个的成员变量-----------------------------------------------------------");
        Field name = clazz.getDeclaredField("name");
        System.out.println(name);

        //获取成员变量的权限修饰符
        System.out.println();
        System.out.println("获取成员变量的权限修饰符-----------------------------------------------------------");
        int modifiers = name.getModifiers();
        System.out.println(modifiers);

        //获取成员变量的名字
        System.out.println();
        System.out.println("获取成员变量的名字-----------------------------------------------------------");
        String n = name.getName();
        System.out.println(n);


        //获取成员变量的数据类型
        System.out.println();
        System.out.println("获取成员变量的数据类型-----------------------------------------------------------");
        Class<?> type = name.getType();
        System.out.println(type);

        //获取成员变量记录的值
        System.out.println();
        System.out.println("获取成员变量记录的值并修改----------------------------------------------------------");
        反射.myreflect1.Student s = new Student("zhangsan");
        name.setAccessible(true);
        String value = (String) name.get(s);
        System.out.println(value);

        //修改对象里面记录的值
        name.set(s, "lisi");
        System.out.println(s);
    }
}

结果:

获取成员方法并调用

package 反射.myreflect1;


import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class MyReflectDemo4 {
     /*
       Class类中用于获取成员方法的方法
            Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的
            Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
            Method getMethod(String name, Class<?>... parameterTypes) :返回单个公共成员方法对象
            Method getDeclaredMethod(String name, Class<?>... parameterTypes):返回单个成员方法对象


       Method类中用于创建对象的方法
            Object invoke(Object obj, Object... args):运行方法
            参数一:用obj对象调用该方法
            参数二:调用方法的传递的参数(如果没有就不写)
            返回值:方法的返回值(如果没有就不写)

        获取方法的修饰符
        获取方法的名字
        获取方法的形参
        获取方法的返回值
        获取方法的抛出的异常

    */

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //1. 获取class字节码文件对象
        Class clazz = Class.forName("反射.myreflect1.Student");


        //2. 获取里面所有的方法对象(包含父类中所有的公共方法)
        System.out.println();
        System.out.println("获取里面所有的方法对象-----------------------------------------------------------");
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

        // 获取里面所有的方法对象(不能获取父类的,但是可以获取本类中私有的方法)
        System.out.println();
        System.out.println("获取里面所有的方法对象(不能获取父类的,但是可以获取本类中私有的方法)-----------------------------------------------------------");
        Method[] methods1 = clazz.getDeclaredMethods();
        for (Method method : methods1) {
            System.out.println(method);
        }

        // 获取指定的单一方法
        System.out.println();
        System.out.println("获取指定的单一方法-----------------------------------------------------------");
        Method m = clazz.getDeclaredMethod("Print2", String.class);
        System.out.println(m);

        // 获取方法的修饰符
        System.out.println();
        System.out.println("获取方法的修饰符-----------------------------------------------------------");
        int modifiers = m.getModifiers();
        System.out.println(modifiers);

        // 获取方法的名字
        System.out.println();
        System.out.println("获取方法的名字-----------------------------------------------------------");
        String name = m.getName();
        System.out.println(name);

        // 获取方法的形参
        System.out.println();
        System.out.println("获取方法的形参-----------------------------------------------------------");
        Parameter[] parameters = m.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }

        //获取方法的抛出的异常
        System.out.println();
        System.out.println("获取方法的抛出的异常----------------------------------------------------------");
        Class[] exceptionTypes = m.getExceptionTypes();
        for (Class exceptionType : exceptionTypes) {
            System.out.println(exceptionType);
        }


        //方法运行
        /*Method类中用于创建对象的方法
        Object invoke(Object obj, Object... args):运行方法
        参数一:用obj对象调用该方法
        参数二:调用方法的传递的参数(如果没有就不写)
        返回值:方法的返回值(如果没有就不写)*/



        System.out.println();
        System.out.println("方法运行----------------------------------------------------------");
        Student s = new Student();
        m.setAccessible(true);
        //参数一s:表示方法的调用者
        //参数二"汉堡包":表示在调用方法的时候传递的实际参数
        String result = (String) m.invoke(s,"你好");
        System.out.println(result);


    }
}

结果:

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值