谈谈对java中反射的理解和细节

反射的定义

反射就是把java类中的各种成分映射成一个个的Java对象,在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。反射机制简单理解为动态获取类中的信息。

反射常用的一些类

类	解释
Class	在反射中表示内存中的一个Java类,Class可以代表的实例类型包括,类和接口、
基本数据类型、数组
Object	Java中所有类的超类
Constructor	封装了类的构造函数的属性信息,包括访问权限和动态调用信息
Field	提供类或接口的成员变量属性信息,包括访问权限和动态修改
Method	提供类或接口的方法属性信息,包括访问权限和动态调用信息

三种获取反射的形式

Class<?> Class.forName(String packageAndClassName);//使用完整的包名和类名调用反射对象
Class<?> 任意类对象.getClass();  //通过对象名的方式调用Class对象
Class<T> 类名.class; //通过类名调用Class对象   

反射常用方法

Constructor[] getConstructors();//获取当前 Class 对应数据类型的所有【非私有化】构造方法对象数组
Constructor[] getDeclaredConstructors();//获取当前 Class 对应数据类型的所有构造方法对象数组,这里可以获取到私有方法
Constructor getConstructor(Class... parameterTypes);//根据指定的参数类型,个数,顺序获取到对应非私有化的Constructor对象
Constructor getDeclaredConstructor(Class... parameterTypes);//根据指定的参数类型,个数,顺序获取到对应非私有化的Constructor对象中
Object newInstance(Object... parameterValues); // 用于构造方法进行实例化操纵
Method[] getMethods();
Method[] getDeclaredMethods();
Method getMethod(String methodName, Class... parameterTypes);
Method getDeclaredMethod(String methodName, Class... parameterTypes);
Object invoke(Object obj, Object... parameterValues); 
Field[] getFields();
Field[] getDeclaredFields();
Field getField(String fieldName);
Field getDeclaredField(String fieldName);
void set(Object obj, Object value);
Object get(Object obj);
void setAccessible(boolean flag); 
public static void setAccessible(AccessibleObject[] array, boolean flag)

有很多小伙伴看到这里是不是头都都大了,有这么多方法,不急不急,其实都是一个套路,换汤不换药的东西 ,我们可以反射所用的方法分为四个类型,一Constructor 二Method 三Field 四setAccessible

下面开始一一解答

反射基本操作

我们先定义实体类(Person)有三个属性 id,age,name(私有),两个公开构造方法,一个私有构造方法,两个公开方法(test,game),两个私有方法(testPrivate)

public class Person {
    private int id;
    private int age;
    private String name;

    public int test = 10;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public Person() {

    }

    private Person(int id) {
        this.id = id;
    }

    public Person(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
    private void testPrivate () {
        System.out.println("类内私有化成员变量");
    }
    private void testPrivate(String name) {
        System.out.println("玩"+name);
    }
    public void test() {
        System.out.println("大吉大利,今晚吃鸡");
    }
    public void game(String name) {
        System.out.println("玩" +name);
    }
    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

反射之一(构造方法--Constructor)

public class ConstructorObjectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 获取定制类型的Class对象
        Class<?> cls = Class.forName("com.itxiao.day09reflect.Person");
        //获取当前Class 对应数据类型的所有非私有化构造方法数组
        Constructor<?>[] constructors = cls.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
        System.out.println("-----------------");
        //暴力反射 获取当前Class对应的数据类型的所有构造方法对象数组,包括私有化构造方法
        Constructor<?>[] declaredConstructors = cls.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }
        System.out.println();
        //根据用户指定的参数类型,顺序,个数获取对应的Constructor构造方法对象,并且非私有的
        Constructor<?> c1 = cls.getConstructor(); //重点
        Constructor<?> c2 = cls.getConstructor(int.class,int.class,String.class);
        System.out.println(c2);
        System.out.println(c1);
        // 根据用户指定的参数类型,顺序,个数获取对应的Constructor构造方法对象,并且可以获取私有的方法
        Constructor<?> c3 = cls.getDeclaredConstructor(int.class);
        System.out.println(c3);
        //通过构造方法实例化类对象
        Person p1 = (Person) c1.newInstance();
        Person p2 = (Person) c2.newInstance(1,23,"张三");

        System.out.println(p1);
        System.out.println(p2);
        /*
        new 构造方法形式局限性很大,通过反射方式操作,可以实现多种多样的类型要求
         */
        Person person =new Person(2,21,"李四");
        System.out.println(person);
        //开启暴力反射的权限问题,直接调用会导致 IllegalAccessException 非法权限异常
        c3.setAccessible(true);
        Person p5 = (Person) c3.newInstance(12);
        System.out.println(p5);
      }
}

反射之二(Method)

public class MethodObjectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //获取指定类型的Class对象
        Class<?> cls = Class.forName("com.itxiao.day09reflect.Person");
        //可以获取Class对象对应类型的所有非私有化对象数组,包括父类继承给子类的成员方法
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println();
         /*
        暴力反射,可以获取Class对象对应类型的所有成员方法对象数组
        ,包含私有方法,但是不包含父类继承给子类的成员方法
         */
        Method[] declaredMethods = cls.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        System.out.println();
        /*
        根据指定的方法名称(methodName) 和 指定的方法参数类型,获取成员方法对象
         */
        Method test = cls.getMethod("test");
        System.out.println(test);
        Method game = cls.getMethod("game", String.class);//重点
        System.out.println(game);
        System.out.println("----------");
          /*
        暴力反射,可以获取Class对象对应类型的所有成员方法对象数组
        ,包含私有方法,但是不包含父类继承给子类的成员方法,仅获取子类自有方法
         */
        Method m1 = cls.getDeclaredMethod("testPrivate");
        System.out.println(m1);
        Method m2 = cls.getDeclaredMethod("testPrivate", String.class);
        System.out.println(m2);
        System.out.println();
        //实例化对象
        Object o = cls.getConstructor().newInstance();
        //非私有化方法 o 表示当前实例化对象
        test.invoke(o);
        game.invoke(o, "PUBG");
        System.out.println();
//        m1.setAccessible(true);
//        m2.setAccessible(true);
        //同时给多个暴力反射的私有化方法给予权限
        AccessibleObject.setAccessible(new AccessibleObject[]{m1,m2},true);
        m1.invoke(o);
        m2.invoke(o, "泥巴");
    }
}

反射之三(Field)

public class FieldObjectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //获取指定类型的Class类型对象
        Class<?> cls = Class.forName("com.itxiao.day09reflect.Person");
        //获取类中所有非私有化成员变量对象数组
        Field[] fields = cls.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println();
        //根据指定的成员变量名称,获取对应的非私有化成员变量
        Field test = cls.getField("test");
        System.out.println(test);
        System.out.println();
        //【暴力反射】 根据指定的成员变量名称,获取对应的成员变量数组,包括私有化的成员变量
        Field id = cls.getDeclaredField("id");
        Field name = cls.getDeclaredField("name");
        System.out.println(id);
        System.out.println(name);
        System.out.println("--------------");
        // Field赋值和取值操作
        //获取当前实例化对象
        Object obj = cls.getConstructor().newInstance();
        AccessibleObject.setAccessible(new AccessibleObject[]{id,name},true);
        //给id赋值
        id.set(obj, 20);
        //给name赋值
        name.set(obj, "狗哥");
        System.out.println(obj);
        System.out.println(id.get(obj));
        System.out.println(name.get(obj));
    }
}

反射的优缺点

优点:

  • 提高了 Java 程序的灵活性和扩展性,降低耦合性,提高自适应能力。

  • 允许程序创建和控制任何类的对象,无需提前硬编码目标类

  • 应用很广,测试工具、框架都用到了反射

缺点:

  • 性能问题:反射是一种解释操作,远慢于直接代码。因此反射机制主要用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用

  • 模糊程序内部逻辑:反射绕过了源代码,无法再源代码中看到程序的逻辑,会带来维护问题

  • 增大了复杂性:反射代码比同等功能的直接代码更复杂

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值