JAVA反射----->看这篇就够了

目录

反射概述

反射获取类对象

反射获取构造器对象

反射获取成员变量对象

反射获取方法对象

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

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

反射的作用-----总结


反射概述

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

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

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

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

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

反射的关键: 反射的第一步都是先得到编译后的Class类对象,然后就可以得到Class的全部成分。 例如:Class c = People.class;

反射的核心思想和关键就是:得到编译以后的class文件对象。

反射的作用:反射是在运行时获取类的字节码文件对象:然后可以解析类中的全部成分

反射获取类对象

反射的第一步:获取Class类的对象

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

方法二:Class c2 = 类名.class

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

public class People {
    private String name;
    private int age;
}
public class TestPeople0 {
    public static void main(String[] args) throws Exception {
//        1.Class类中的静态方法
        Class c = Class.forName("one.People");
        System.out.println(c);
//        2.类名.class
        Class c0 = People.class;
        System.out.println(c0);
//        3.获取对象对应类的Class对象
        People p = new People();
        Class c1 = p.getClass();
        System.out.println(c1);
    }

}

反射获取构造器对象

获得class对象 ===》  获取构造器 ===》 创建对象

第二步:获得Constructor对象

提取构造器,具体使用在代码中:

1.Constructor[] constructors = c.getConstructors();

2.Constructor[] constructors = c.getDeclaredConstructors();

3.Constructor constructor = c.getConstructor();

4.Constructor constructor = c.getDeclaredConstructor();

Constructor<?>[] getConstructors​()

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

Constructor<?>[] getDeclaredConstructors​()

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

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

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

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

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

public class People {
    private String name;
    private int age;
    public People(){
        System.out.println("无参构造!");
    }
    private People(String name, int age){
        this.name = name;
        this.age = age;
        System.out.println("有参构造!");
    }
public class TestPeople1 {
    public void getConstructors(){
        //1.获取类对象
        Class c = People.class;
        //2.提取类中的全部构造器对象----私有的拿不到,只能拿public的
        Constructor[] constructors = c.getConstructors();
        //遍历构造器
        for(Constructor constructor : constructors)
                System.out.println(constructor.getName()+"--->"+constructor.getParameterCount());   //名字--->参数个数

    }
    public void getDeclaredConstructors(){
        //1.获取类对象
        Class c = People.class;
        //2.提取类中的全部构造器对象----私有的也能拿到
        Constructor[] constructors = c.getDeclaredConstructors();
        //遍历构造器
        for(Constructor constructor : constructors)
            System.out.println(constructor.getName()+"--->"+constructor.getParameterCount());   //名字--->参数个数

    }

    public void getConstructor() throws NoSuchMethodException {
        //1.获取类对象
        Class c = People.class;
        //2.提取类中的一个构造器对象--根据参数拿对应构造器---只能拿public的
        Constructor constructor = c.getConstructor();
        //名字--->参数个数
        System.out.println(constructor.getName()+"--->"+constructor.getParameterCount());

    }
    public void getDeclaredConstructor() throws NoSuchMethodException {
        //1.获取类对象
        Class c = People.class;
        //2.提取类中的一个构造器对象--根据参数拿对应构造器---私有的也能拿到
        Constructor constructor = c.getDeclaredConstructor(String.class, int.class);
        //名字--->参数个数
        System.out.println(constructor.getName()+"--->"+constructor.getParameterCount());

    }

    public static void main(String[] args) throws Exception {
        TestPeople1 a = new TestPeople1();
        a.getConstructors();
        a.getDeclaredConstructors();
        a.getConstructor();
        a.getDeclaredConstructor();
    }
}

 第三步创建对象: 

constructor.setAccessible(true);  暴力开权限,反射可以破坏其封装性--私有的才需要开权限,公有的不需要
Object p = constructor.newInstance();   根据对应的构造器,创建对象---可强制转换     

以下代码是在上面的基础上进行增添,具体使用在代码中:
import java.lang.reflect.Constructor;

public class TestPeople2 {
    public void getObject() throws Exception {
        //1.获取类对象
        Class c = People.class;
        //2.提取类中的一个构造器对象--根据参数拿对应构造器---私有的也能拿到
        Constructor constructor = c.getDeclaredConstructor(String.class, int.class);
        //名字--->参数个数
        System.out.println(constructor.getName()+"--->"+constructor.getParameterCount());
        //私有构造器报错,不能创建对象,,需要暴力反射--开权限--setAccessible(true)
        constructor.setAccessible(true);    //只针对这一次有效
        Object p = constructor.newInstance("小明", 18);   //创建对象People,18岁的小明
    }

    public static void main(String[] args) throws Exception {
        TestPeople2 p = new TestPeople2();
        p.getObject();
    }
}

反射获取成员变量对象

获得class对象 ===》  获取成员变量 ===》 取值或赋值

第一步:获得class对象

第二步:获得Field对象

Field[] fields = c.getDeclaredFields();    获取全部成员变量
Field field = c.getDeclaredField("name"); 获取其中一个成员变量----根据变量名称获取

Field[] getFields​()

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

Field[] getDeclaredFields​()

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

Field getField​(String name)

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

Field getDeclaredField​(String name)

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

第三步:获取值或赋值

Field field = c.getDeclaredField("age");

get方法,取值        field.get(对象);

set方法,赋值        field.set(对象, 值);

void set​(Object obj, Object value):

赋值

Object get​(Object obj)

获取值。 

具体使用在代码中:

import java.lang.reflect.Field;
public class TestPeople3 {
    public void getDeclaredFields(){
        //1.获取class对象
        Class c = People.class;
        //2.获取全部成员变量
        Field[] fields = c.getDeclaredFields();
        //遍历
        for(Field field : fields)
            System.out.println(field.getName() + "--->" + field.getType()); //名字--->类型
    }
    public void getDeclaredField() throws Exception {
        //1.获取class对象
        Class c = People.class;
        //2.获取其中一个成员变量----根据名称获取某个成员变量
        Field field = c.getDeclaredField("age");
        //输出    名字--->类型
        System.out.println(field.getName() + "--->" + field.getType());

        //3.赋值
        field.setAccessible(true);  //暴力开权限---private成员变量不能直接操作
        People p = new People();
        field.set(p, 18);
        System.out.println("赋值age:"+p.getAge());

        //4.取值
        int age = (int)field.get(p);
        System.out.println("取值age:"+age);
        
    }
    public static void main(String[] args) throws Exception {
        TestPeople3 p = new TestPeople3();
        p.getDeclaredFields();
        p.getDeclaredField();
    }

}

反射获取方法对象

获得class对象 ===》  获取方法 ===》 触发执行方法

第一步:获得class对象

第二步:获得Method对象

Method[] getMethods​()

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

Method[] getDeclaredMethods​()

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

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

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

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

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

第三步:Method类中用于触发执行的方法

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

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

运行方法

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

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

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

具体使用在代码中:

import java.lang.reflect.Method;

public class TestPeople4 {

    public void getDeclareMethods(){
        //1.获取类对象
        Class c = People.class;
        //2.提取全部方法,包括私有的
        Method[] methods = c.getDeclaredMethods();
        //遍历
        for (Method method : methods)   //名字--->返回类型--->参数个数
                System.out.println(method.getName()+"--->"+method.getReturnType()+"--->"+method.getParameterCount());
    }
    public void getDeclareMethod() throws Exception {
        //1.获取类对象
        Class c = People.class;
        //2.提取某一个方法,根据名字
        Method method1 = c.getDeclaredMethod("setAge", int.class);
        Method method2 = c.getDeclaredMethod("getAge");
        //名字--->返回类型--->参数个数
        System.out.println(method1.getName()+"--->"+method1.getReturnType()+"--->"+method1.getParameterCount());
        System.out.println(method2.getName()+"--->"+method2.getReturnType()+"--->"+method2.getParameterCount());

        //3.方法的触发执行
        //如果方法不是public的,需要打开权限(暴力反射),然后再触发执行----setAccessible(boolean)
        People p = new People();
        Object a1 = method1.invoke(p, 20);
        Object a2 = method2.invoke(p);
        //若方法是无返回结果的,则返回的是null
        System.out.println(a1);
        System.out.println(a2);
    }
    public static void main(String[] args) throws Exception {
        TestPeople4 p = new TestPeople4();
        p.getDeclareMethods();
        p.getDeclareMethod();
    }
}

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

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

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

具体使用在代码中:


import java.lang.reflect.Method;
import java.util.ArrayList;

public class TestDemo5 {
    public static void main(String[] args) throws Exception {
        // 需求:反射实现泛型擦除后,加入其他类型的元素
        //编译成Class文件进入运行阶段的时候,泛型会自动擦除。反射是作用在运行时的技术,此时已经不存在泛型了。
        //故反射不受泛型的约束
        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


        ArrayList<Integer> lists3 = new ArrayList<>();
        lists3.add(11);
        lists3.add(22);
//      list3.add("小孩"); 类型不符合,错误


        Class c = lists3.getClass();  //ArrayList.class
        //获取c类中的add方法------不受泛型Integer的约束
        Method add = c.getDeclaredMethod("add", Object.class);
        //判断添加是否成功
        boolean ans = (boolean) add.invoke(lists3, "小孩");
        System.out.println(ans);
        System.out.println(lists3);
    }
}

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

下面是一个实例:

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

// 提供一个通用框架,支持保存所有对象的具体信息。
public class TestDemo2 {
    //保存任意类型的对象 Object
    public static void save(Object obj){
        try (//文件输出到data.txt中
             PrintStream ps = new PrintStream(new FileOutputStream("demo1/src/data.txt", true));
        ){
            //1.获取该类对象
            Class c = obj.getClass();
            ps.println("---------------> " + c.getSimpleName() + " <---------------");
            //2.提取该对象的全部成员变量
            Field[] fields = c.getDeclaredFields();
            for (Field field: fields){
                //暴力开权限
                field.setAccessible(true);
                //获取成员变量名字
                String name = field.getName();
                //取值
                String value = field.get(obj) + "";
                ps.println(name  + "=" + value);
            }
        }catch (IllegalAccessException e) {
                throw new RuntimeException(e);

        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        Worker w = new Worker(22, '男', "张三");
        save(w);
    }
    
}

反射的作用-----总结

  1. 可以在运行时得到一个类的全部成分然后操作。
  2. 可以破坏封装性。(很突出)
  3. 也可以破坏泛型的约束性。(很突出)
  4. 更重要的用途是适合:做Java高级框架 基本上主流框架都会基于反射设计一些通用技术功能。

如果有错误,大哥们指出来,我会改的!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

代码不会敲

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

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

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

打赏作者

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

抵扣说明:

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

余额充值