java反射三种方法_反射及暴力反射

b46456e44fd15b1825af86cbdb83cd7d.png

作者:逯小逯

出自:SegmentFault 思否

原文:segmentfault.com/a/1190000037432381


反射

一、概述

(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文件的执行流程

5e9ca79edc85e257173e68ab4470d609.png

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)使用反射会模糊程序内部实际要发生的事情,程序人员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术会带来维护问题。反射代码比响应的直接代码更复杂。解决这些问题的最佳方案是保守的使用反射--尽在它可以真正增加灵活性的地方--记录其在目标来中的使用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值