关于java:反射及暴力反射

53次阅读

共计 6321 个字符,预计需要花费 16 分钟才能阅读完成。

反射及暴力反射

反射

一、概述

(1)反射的定位是很重要的,JVM 和底层框架都离不开反射
(2) 反射的原理是拿到你的 class 文件里的数据, 进行数据的操作 (CURD)
(3) 反射提供了丰盛的办法, 来操作类里的各种数据 (属性 / 办法 / 结构)
(4)REflection(反射) 是 Java 程序开发语言的特色之一, 它容许运行中的 Java 程序对本身进行查看, 或者说 ” 自审 ”, 也有称作 ” 自省 ”。
反射十分弱小,它甚至能间接操作程序的公有属性,private 的只能类外部拜访,内部是不行的,但这个规定被反射赤裸裸的突破了。

为什么须要反射?

有一个类, 我想要拜访这个类中的成员变、构造方法和成员办法,失常状况下,咱们拿到的是这个类的.java 文件, 那么我间接通过 new 关键字创立一个类的实例对象, 而后通过这个实例对象就能够拜访这个类的成员变量、构造方法、成员办法。然而当初我没有这个类的.java 文件,而是只能拿到了这个类的.class 文件,那么如何去拜访到这个类中的成员变量、构造方法和成员办法?这就是反射机制解决的问题。
在开发的世界里,spring 就是业余的组织它能帮咱们创建对象,治理对象,咱们不在 new 对象,而间接从 spring 提供的容器中 beans 获取即可,Beans 底层其实就是一个 Map<String,Object>, 最终通过 getBean(“user”)来获取, 而这其中最外围的实现就是利用反射技术。
总结:应用反射能够赋予 jvm 动静编译的能力,否则类的元数据信息只能用动态编译的形式实现。Java 反射是 Java 被视为动静 (或准动静) 语言的一个要害性质。

二、Class 对象

Class 对象封装了.class 文件里的所有数据, 并提供了很多办法来操作数据

1、概述

(1)Class 类的实例示意正在运行的 Java 应用程序中的类和接口。
(2)枚举是一品种,正文是一种接口,每个数组属于被映射为 Class 对象的一个类,所有具备雷同元素类型和维数的数组都共享该 Class 对象。
(3)根本的 Java 类型 (boolean、byte、char、short、int、long、float 和 double) 和关键字 void 也示意为 Class 对象。

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

(1)static Class<?>forName(String className)— 返回与带有给定字符串名的类或接口相关联的 Class 对象
(2) 类名.class
(3)对象.getClass()
留神: 同一个字节码文件 (.class) 在同一个程序当中只会被加载一次, 不管用哪一种。每一个类对应一个字节码文件(.class)

3、.java 文件的执行流程

4、罕用办法及测试

(1)创立 Student 类

package cn.tedu.reflection;
// 测试 反射
public class Student {
 public String name = "皮皮霞";
 public int age = 22 ;
    // 提供构造方法 - 右键 -generate...constructor...
    public Student() {}
    public Student(String name) {this.name = name;}
    public Student(int age) {this.age = age;}
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
`public void show(){System.out.println("show()...");
    }
    public void test(String n){System.out.println("test()..."+n);
    }
    // 为了能查看属性值, 而不是地址值, 提供重写的 toString()
    // 右键 -generate...toString()-ok
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}`

(2)创立测试类

package cn.tedu.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
// 测试 反射
public class Test1_Reflect {public static void main(String[] args) throws Exception {//method();// 通过反射的技术, 获取 Class 对象
//        method2();// 通过反射的技术, 获取类中的所有构造方法
//        method3();// 通过反射的技术, 获取成员办法
//        method4();// 通过反射的技术, 获取成员变量
        method5();// 通过反射的技术, 创立实例}
    // 通过反射的技术, 创立实例
    private static void method5() throws Exception {
        //1, 获取 Class 对象
        Class<Student> clazz = Student.class;
        //2, 创立实例
        //newInstance()-- 会触发构造方法 -- 触发无参结构
        Student s = clazz.newInstance();
        //s = Student{name='皮皮霞', age=22}
        System.out.println("s =" + s);

        //3, 需要: 能够触发含参结构吗? 能够 - 然而你得指定想要触发哪个含参结构
        // -- 参数是 class 对象类型, 和含参结构的参数类型匹配
        //public Student(String name){} -- new Student("jack");
        Constructor<Student> c = clazz.getConstructor(String.class);
        Student s2 = c.newInstance("jack");
        //s2 = Student{name='jack', age=22}
        System.out.println("s2 =" + s2);
    }
    // 通过反射的技术, 获取成员变量
    private static void method4() throws ClassNotFoundException {
        //1, 获取 Class 对象
        Class<?> clazz = Class.forName("cn.tedu.reflection.Student");
        //2, 获取成员变量 --!!!! 只能获取 public 的!!!!
        Field[] fs = clazz.getFields();
        //3, 遍历数组, 获取每个 Field
        for (Field f : fs) {
            // 获取变量名
            System.out.println(f.getName() );
            // 获取变量类型
            System.out.println(f.getType().getName());
        }
    }
    // 通过反射的技术, 获取成员办法
    private static void method3() {
        //1, 获取 Class 对象
        Class clazz = Student.class;
        //2, 获取成员办法们
        Method[] ms = clazz.getMethods();
        //3, 遍历数组, 获取每个 Method
        for (Method m : ms) {
            // 获取办法名
            System.out.println(m.getName());
            // 获取办法参数
            Class<?>[] cs = m.getParameterTypes();
            System.out.println(Arrays.toString(cs) );
        }
    }
    // 通过反射的技术, 获取类中的构造方法
    private static void method2() {
        //1, 获取 Class 对象
        Class<Student> clazz = Student.class;
        //2, 获取构造方法们
        Constructor<?>[] cs = clazz.getConstructors();
        //3,foreach 循环获取每个构造方法
        for (Constructor<?> c : cs) {
            // 获取构造方法名
            System.out.println(c.getName());
            // 获取构造方法的参数
            Class<?>[] cs2 = c.getParameterTypes();
            System.out.println(Arrays.toString(cs2));
        }
    }
    // 通过反射的技术, 获取 Class 对象 // 三种形式
    private static void method() throws ClassNotFoundException {//        -- static Class<?> forName(String className)-- 参数是类的全门路
        Class<?> clazz = Class.forName("java.lang.Object");
//        -- 类名.class
        Class<String> clazz2 = String.class;
//        -- 对象.getClass()-- 泛型下限, 最大是 String 类型, 束缚了元素的类型 <=String 类型
        Class<? extends String> clazz3 = new String().getClass();

        System.out.println("clazz =" + clazz);
        System.out.println("clazz2 =" + clazz2);
        System.out.println("clazz3 =" + clazz3);
    }
}

暴力反射

1、概述

暴力的获取类中的公有资源顺便获取公开的。
暴力反射和一般反射的反射原理是一样的,都是拿到.class 文件中的所有数据并封装成 Class 对象, 通过各种办法来操作数据, 只不过是换了一套 API

2、罕用办法

–getFields()获取成员变量! 只能获取 public 的!!!!
–getFirld()
–getMenthods()获取成员办法们
–getMenthod()
–getConstructors() 获取构造方法们
– 以上的办法, 都能够获取类里的资源, 只不过要求这些资源都是 public 的
– 以下的办法, 都能够实现暴力反射
–getDeclaredFields()
–getDeclaredField()
–getDeclaredMethods()
–getDeclaredMethod()
–getDeclaredConstructors()
–getDeclaredConstruction()

3、测试

(1)创立 Person 类

package cn.tedu.reflection;
// 测试 暴力反射
public class Person {
    public String name ;
    private int age ;
    // 提供结构 -- 右键 -generate...
    public Person() {}
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    private Person(int age) {this.age = age;}
    private Person(String name) {this.name = name;}

    public void show(int a){System.out.println("show()..."+a);
    }
    private void test(String n){System.out.println("test()..."+n);
    }
    // 为了查看属性值, 重写的 toString()-- 右键 -generate...
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

(2)创立测试类

package cn.tedu.reflection;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

// 测试 暴力反射
// 外围: 用对 API(getDeclaredXxx())  +  设置拜访权限(setAccessible())
public class Test2_BaoliReflect {public static void main(String[] args) throws Exception {//        method();// 暴力反射成员变量
        method2();// 暴力反射成员办法}
    // 暴力反射成员办法
    private static void method2() throws Exception {
        //1, 反射 Class 对象
        Class<Person> clazz = Person.class;
        //2, 反射成员办法们~~
        Method[] ms = clazz.getDeclaredMethods();
        //3, 遍历
        for (Method m : ms) {
            // 获取办法名
            System.out.println(m.getName() );
        }
        //4, 执行指定的办法
     //getDeclaredMethod(m,n)- m 是办法名 - n 是办法的参数类型的 Class 对象
        Method m = clazz.getDeclaredMethod("test", String.class);
        //!!!!!6,设置拜访权限!!!!!!
        m.setAccessible(true);
        //5, 执行办法 --invoke(m,n)-- m 是哪个对象 -- n 是具体的办法须要的参数
        Object obj = clazz.newInstance();
        m.invoke(obj,"hellotest");
    }
    // 暴力反射成员变量
    private static void method() throws Exception {
        //1, 反射 Class 对象
        Class<Person> clazz = Person.class;
        //2, 反射成员变量们~~
        Field[] fs = clazz.getDeclaredFields();
        //3, 遍历
        for (Field f : fs) {
            // 获取变量名
            System.out.println(f.getName());
            // 获取变量类型
            System.out.println(f.getType().getName());
        }
        //4, 获取指定的属性
        Field f = clazz.getDeclaredField("age");
        //!!7, 设置拜访权限, 否则 IllegalAccessException
        f.setAccessible(true);
        //5, 设置属性的值 --set(m,n)-- m 是要给哪个对象 -- n 是具体的值
        Object obj = clazz.newInstance();
        f.set(obj,100);
        //6, 获取属性的值
        System.out.println(f.get(obj) );
    }
}

4、反射机制的毛病

(1)性能问题。应用反射机制基本上是一种解释操作,咱们能够通知 JVM,咱们心愿做什么并且它满足咱们的要求,用于字段和办法接入时反射要远满于间接代码。
性能问题的水平取决于程序中是如何应用反射的,如果它作为程序运行中绝对很少波及的局部,迟缓的性能将不会是一个问题。
(2)应用反射会含糊程序外部理论要产生的事件,程序人员心愿在源代码中看到程序的逻辑,反射等绕过了源代码的技术会带来保护问题。反射代码比响应的间接代码更简单。解决这些问题的最佳计划是激进的应用反射 – 尽在它能够真正减少灵活性的中央 – 记录其在指标来中的应用。

正文完
 0