Java中的反射

目录

一、反射概述

1、反射概述

2、反射的核心思想

二、反射获取类对象的三种方式

1、反射的第一步是什么?

2、获取Class类的对象的三种方式

3、演示代码

三、反射获取构造器对象

1.使用反射技术获取构造器对象

2.演示代码

3. Constructor类中用于创建对象的方法

4.演示代码

 5、注意

四、反射获取成员变量对象

1、反射技术获取成员变量对象

2、代码演示

 3、Field类中用于取值、赋值的方法

4、代码展示

5、注意

五、反射获取方法对象

1、反射技术获取方法对象

2.、Method类中用于触发执行的方法

3、代码展示

4、注意

六、反射的作用-绕过编译阶段为集合添加数据

七、反射的作用-通用框架的底层原理

1.主要代码

 八、反射的作用


一、反射概述

1、反射概述

反射是指对于任何一个Class类,在"运行的时候"都可以直接得到这个类全部成分。

在运行时,可以直接得到这个类的构造器对象:Constructor

在运行时,可以直接得到这个类的成员变量对象:Field

在运行时,可以直接得到这个类的成员方法对象:Method

这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制。

2、反射的核心思想

是得到编译以后的class文件对象。

二、反射获取类对象的三种方式

1、反射的第一步是什么?

获取Class类对象,这样才可以解析类的全部成分

2、获取Class类的对象的三种方式

方式一:Class c1 = Class.forName(“全类名”);

方式二:Class c2 = 类名.class

方式三:Class c3 = 对象.getClass();

3、演示代码

public static void main(String[] args) throws Exception {
        //1、Class类中的一个静态方法:forname(权限名:包名+类名)
        Class c = Class.forName("com.wfl.d2_reflect_class.Student");
        System.out.println(c);  //Student.class

        //2、类名.class
        Class c2 = Student.class;
        System.out.println(c2);

        //3、对象.getClass() 获取对象对应的Class对象
        Student s = new Student();
        Class c3 = s.getClass();
        System.out.println(c3);
    }

3.1、结果展示 

 

三、反射获取构造器对象

1.使用反射技术获取构造器对象

1.1.反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。

1.2.Class类中用于获取构造器的方法

方法

说明

Constructor<?>[] getConstructors​()

返回所有构造器对象的数组(只能拿public的)

Constructor<?>[] getDeclaredConstructors​()

返回所有构造器对象的数组,存在就能拿到

Constructor<T> getConstructor​(Class<?>... parameterTypes)

返回单个构造器对象(只能拿public的)

Constructor<T> getDeclaredConstructor​(Class<?>... parameterTypes)

返回单个构造器对象,存在就能拿到

2.演示代码

//1、getConstructors:
    //获取全部构造器:只能获取pubilc修饰的构造器。
    //Constructor[] getConstructors()
    @Test
    public void getConstructors() {
        //a.第一步获取类对象
        Class c = Student.class;
        //b.获取全部构造器(只能获取pubilc修饰的构造器)
        Constructor[] constructors = c.getConstructors();
        //c.遍历构造器
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "==>" + constructor.getParameterCount());
        }
    }

    //2、getDeclaredConstructors():
    //获取全部构造器:只能只要你敢写,这里就都可以获取到
    @Test
    public void getDeclaredConstructors() {
        //a.第一步获取类对象
        Class c = Student.class;
        //b.获取全部构造器
        Constructor[] constructors = c.getDeclaredConstructors();
        //c.遍历构造器
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "==>" + constructor.getParameterCount());
        }
    }

    //3、getConstructor(Class...parameterTypes)
    //获取某个构造器:只能获取pubilc修饰的某个构造器。
    @Test
    public void getConstructor() throws Exception {
        //a.第一步获取类对象
        Class c = Student.class;
        //b.获取某个构造器(只能获取pubilc修饰的某个构造器。获取无参构造器)
        Constructor constructor = c.getConstructor();

        System.out.println(constructor.getName() + "==>" + constructor.getParameterCount());
    }

        //4、getDeclaredConstructor(Class...parameterTypes)
        //获取某个构造器:只能只要你敢写,这里就能拿到
        @Test
        public void getDeclaredConstructor () throws Exception {
            //a.第一步获取类对象
            Class c1 = Student.class;
            //b.获取某个构造器(无参构造器)
            Constructor cons = c1.getDeclaredConstructor();
            System.out.println(cons.getName() + "==>" + cons.getParameterCount());

            //c.定义某个有参构造器
            Constructor cons1 = c1.getDeclaredConstructor(String.class,int.class);
            System.out.println(cons1.getName() + "==>" + cons1.getParameterCount());
        }

2.1.结果展示

 

3. Constructor类中用于创建对象的方法

符号

说明

T newInstance​(Object... initargs)

根据指定的构造器创建对象

public void  setAccessible(boolean flag)

设置为true,表示取消访问检查,进行暴力反射

4.演示代码

 public void getDeclaredConstructor () throws Exception {
        //a.第一步获取类对象
        Class c1 = Student.class;
        //b.获取某个构造器(无参构造器)
        Constructor cons = c1.getDeclaredConstructor();
        System.out.println(cons.getName() + "==>" + cons.getParameterCount());

        //如果遇到了私有的构造器,可以暴力反射
        cons.setAccessible(true); //权限被打开了

        Student s = (Student) cons.newInstance();
        System.out.println(s);

        System.out.println("------------------------------");

        //c.定义某个有参构造器
        Constructor cons1 = c1.getDeclaredConstructor(String.class,int.class);
        System.out.println(cons1.getName() + "==>" + cons1.getParameterCount());

        Student s1 = (Student) cons1.newInstance("商务卡", 1000);
        System.out.println(s1);
    }

4.1、结果展示

 

 5、注意

反射可以破坏封装性,私有的方法也可以被执行。

四、反射获取成员变量对象

1、反射技术获取成员变量对象

1.1、反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。

1.2、Class类中用于获取成员变量的方法

方法

说明

Field[] getFields​()

返回所有成员变量对象的数组(只能拿public的)

Field[] getDeclaredFields​()

返回所有成员变量对象的数组,存在就能拿到

Field getField​(String name)

返回单个成员变量对象(只能拿public的)

Field getDeclaredField​(String name)

返回单个成员变量对象,存在就能拿到

2、代码演示

/**
        1、获取全部成员变量
        Field[] getDeclaredFields();
        获得所有的成员变量对应的Field对象,只要声明了就可以得到
     */
    @Test
    public void getDeclaredFields(){
        //a.定位Class对象
        Class c = Student.class;
        //b.定位全部成员变量
        Field[] f = c.getDeclaredFields();
        //c.遍历一下
        for (Field field : f) {
            System.out.println(field.getName()+"==>"+field.getType());
        }
    }
    /**
     2、获取某个成员变量
     Field getDeclaredField();
     获得所有的成员变量对应的Field对象,只要声明了就可以得到
     */
    @Test
    public void getDeclaredField() throws Exception {
        //a.定位Class对象
        Class c = Student.class;
        //b.根据名称定位某个成员变量
        Field f = c.getDeclaredField("age");
        System.out.println(f.getName()+"==>"+f.getType());
    }

 2.1、结果展示

 3、Field类中用于取值、赋值的方法

符号

说明

void set​(Object obj, Object value):

赋值

Object get​(Object obj)

获取值。 

4、代码展示

@Test
    public void getDeclaredField() throws Exception {
        //a.定位Class对象
        Class c = Student.class;
        //b.根据名称定位某个成员变量
        Field f = c.getDeclaredField("age");

        f.setAccessible(true);   //暴力打开权限

        //c.赋值
        Student s = new Student();
        f.set(s,18);  //s.setAge(18);
        System.out.println(s);

        //d取值
        int age = (int) f.get(s);
        System.out.println(age);
    }

 4.1、结果展示

5、注意

 如果某成员变量是非public的,需要打开权限(暴力反射),然后再取值、赋值 setAccessible(boolean)

五、反射获取方法对象

1、反射技术获取方法对象

1.1、反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。

1.2、Class类中用于获取成员方法的方法

方法

说明

Method[] getMethods​()

返回所有成员方法对象的数组(只能拿public的)

Method[] getDeclaredMethods​()

返回所有成员方法对象的数组,存在就能拿到

Method getMethod​(String name, Class<?>... parameterTypes) 

返回单个成员方法对象(只能拿public的)

Method getDeclaredMethod​(String name, Class<?>... parameterTypes)

返回单个成员方法对象,存在就能拿到

2.、Method类中用于触发执行的方法

符号

说明

Object invoke​(Object obj, Object... args)

运行方法

参数一:用obj对象调用该方法

参数二:调用方法的传递的参数(如果没有就不写)

返回值:方法的返回值(如果没有就不写)

3、代码展示

 /**
        1、提取全部方法:包括私有的
     */
    @Test
    public void getDeclardMethods() {
        //a.获取类对象
        Class c = Dog.class;
        //b.提取全部方法:包括私有的
        Method[] methods = c.getDeclaredMethods();
        //c.遍历全部方法
        for (Method method : methods) {
            System.out.println(method.getName()+"返回值类型"+method.getReturnType()+"参数个数:"+method.getParameterCount());
        }
    }

    /**
     1、提取某个方法
     */
    @Test
    public void getDeclardMethod() throws Exception {
        //a.获取类对象
        Class c = Dog.class;
        //b.提取某个方法
        Method m1 = c.getDeclaredMethod("eat");
        Method m2 = c.getDeclaredMethod("eat",String.class);

        //暴力打开权限
        m1.setAccessible(true);
        m2.setAccessible(true);

        //c.触发方法的执行
        Dog d = new Dog();
        //注意没有返回结果,就返回null
        Object result = m1.invoke(d);
        System.out.println(result);

        Object result2 = m2.invoke(d,"骨头");
        System.out.println(result2);

    } /**
        1、提取全部方法:包括私有的
     */
    @Test
    public void getDeclardMethods() {
        //a.获取类对象
        Class c = Dog.class;
        //b.提取全部方法:包括私有的
        Method[] methods = c.getDeclaredMethods();
        //c.遍历全部方法
        for (Method method : methods) {
            System.out.println(method.getName()+"返回值类型"+method.getReturnType()+"参数个数:"+method.getParameterCount());
        }
    }

    /**
     1、提取某个方法
     */
    @Test
    public void getDeclardMethod() throws Exception {
        //a.获取类对象
        Class c = Dog.class;
        //b.提取某个方法
        Method m1 = c.getDeclaredMethod("eat");
        Method m2 = c.getDeclaredMethod("eat",String.class);

        //暴力打开权限
        m1.setAccessible(true);
        m2.setAccessible(true);

        //c.触发方法的执行
        Dog d = new Dog();
        //注意没有返回结果,就返回null
        Object result = m1.invoke(d);
        System.out.println(result);

        Object result2 = m2.invoke(d,"骨头");
        System.out.println(result2);

    }

3.1、结果展示

 

4、注意

如果某成员方法是非public的,需要打开权限(暴力反射),然后再触发执行 setAccessible(boolean)

六、反射的作用-绕过编译阶段为集合添加数据

1、反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他任意类型的元素

2、泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成Class文件进入运行阶段的时候,其真实类型都是ArrayList了,泛型相当于被擦除了。

3、演示代码

3.1介绍:一开始定义一个Integer的泛型,后经过反射可以为其添加String类型的数据。但是有一招简单的方法可以实现,就是将一个集合的数据赋值给另一个集合,给另一个添加,就可以添加任意类型的数据了。

    public static void main(String[] args) throws Exception {
        //需求:反射现实泛型擦除后,加入其他类型的元素
        ArrayList<String> lists1 = new ArrayList<>();
        ArrayList<Integer> lists2 = new ArrayList<>();

        System.out.println(lists1.getClass());
        System.out.println(lists2.getClass());

        System.out.println(lists1.getClass() == lists2.getClass()); //ArrayList.class

        System.out.println("-------------------");
        ArrayList<Integer> lists3 = new ArrayList<>();
        lists3.add(22);
        lists3.add(23);
//        lists3.add("小王");

        Class c = lists3.getClass();

        Method add = c.getMethod("add", Object.class);

        Boolean b = (Boolean) add.invoke(lists3, "小王");
        System.out.println(b);

        System.out.println(lists3);



//简化实现  没有用反射
        ArrayList lists4 = lists3;
        lists4.add("白马");
        lists4.add("白马");
        lists4.add("黑马");
        System.out.println(lists4);
        System.out.println(lists3);

    }

七、反射的作用-通用框架的底层原理

需求:给你任意一个对象,在不清楚对象字段的情况可以,可以把对象的字段名称和对应值存储到文件中去。

1.主要代码

package com.wfl.d7_reflect_framework;


import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;

public class MybatisUtil {
    /**
        保存对象
     * @param obj
     */
    public static void save(Object obj){
        try (
                PrintStream ps = new PrintStream(new FileOutputStream("D:\\code\\javasepromax\\junit-reflect-annotation-proxy-app\\src\\data.txt",true));
                ){
            //1、提起这个类的全部成员变量:只有反射可以解决
            Class c = obj.getClass();        //  c.getSimpleName()获取当前类名      c.getName获取当前权限名:包名+类名
            ps.println("========================"+c.getSimpleName()+"=====================");
            //2、提取它的全部成员变量
            Field[] fields = c.getDeclaredFields();

            //3、获取成员变量的信息
            for (Field field : fields) {
                String name = field.getName();
                //提取本成员变量在obj对象的取值
                field.setAccessible(true);
                String value = field.get(obj)+"";
                ps.println(name+"="+value);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

1.1结果:打印到指定的TXT文件中

 八、反射的作用

1、可以在运行时得到一个类的全部成分然后操作。

2、可以破坏封装性。(很突出)

3、也可以破坏泛型的约束性。(很突出)

4、更重要的用途是适合:做Java高级框架

5、基本上主流框架都会基于反射设计一些通用技术功能。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

꧁༺๑小王不是程序员๑༻꧂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值