反射及暴力反射

反射

一、概述

(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)应用反射会含糊程序外部理论要产生的事件,程序人员心愿在源代码中看到程序的逻辑,反射等绕过了源代码的技术会带来保护问题。反射代码比响应的间接代码更简单。解决这些问题的最佳计划是激进的应用反射--尽在它能够真正减少灵活性的中央--记录其在指标来中的应用。