一篇文章带你深入理解java反射机制

反射

Reflection(反射)是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,也有称作“自省”。反射非常强大,它甚至能直接操作程序的私有属性。我们前面学习都有一个概念,private的只能类内部访问,外部是不行的,但这个规定被反射赤裸裸的打破了。

反射就像一面镜子,它可以在运行时获取一个类的所有信息,可以获取到任何定义的信息(包括成员变量,成员方法,构造器等),并且可以操纵类的字段、方法、构造器等部分。

为什么需要反射:

好好的我们new User(); 不是很好,为什么要去通过反射创建对象呢?那我要问你个问题了,你为什么要去餐馆吃饭呢?例如:我们要吃个牛排大餐,如果我们自己创建,就什么都得管理。

好处是,每一步做什么我都很清晰,坏处是什么都得自己实现,那不是累死了。牛接生你管,吃什么你管,屠宰你管,运输你管,冷藏你管,烹饪你管,上桌你管。就拿做菜来说,你能有特级厨师做的好?

那怎么办呢?有句话说的好,专业的事情交给专业的人做,饲养交给农场主,屠宰交给刽子手,烹饪交给特级厨师。那我们干嘛呢?

我们翘起二郎腿直接拿过来吃就好了。再者,饭店把东西做好,不能扔到地上,我们去捡着吃吧,那不是都成原始人了。那怎么办呢?很简单,把做好的东西放在一个容器中吧,如把牛排放在盘子里。

在开发的世界里,spring就是专业的组织,它来帮我们创建对象,管理对象。我们不在new对象,而直接从spring提供的容器中beans获取即可。Beans底层其实就是一个Map,最终通过getBean(“user”)来获取。而这其中最核心的实现就是利用反射技术。

总结一句,类不是你创建的,是你同事或者直接是第三方公司,此时你要或得这个类的底层功能调用,就需要反射技术实现。有点抽象,别着急,我们做个案例,你就立马清晰。

反射Class类对象

  • Class.forName(“类的全路径”);
  • 类名.class
  • 对象.getClass();

常用方法

  • 获得包名、类名
  • getPackage().getName()//包名
  • getSimpleName()//类名
  • getName()//完整类名

!!成员变量定义信息

  • getFields()//获得所有公开的成员变量,包括继承的变量
  • getDeclaredFields()//获得本类定义的成员变量,包括私有,不包括继承的变量
  • getField(变量名)
  • getDeclaredField(变量名)

!!构造方法定义信息

  • getConstructor(参数类型列表)//获得公开的构造方法
  • getConstructors()//获得所有公开的构造方法
  • getDeclaredConstructors()//获得所有构造方法,包括私有
  • getDeclaredConstructor(int.class, String.class)

方法定义信息

  • getMethods()//获得所有可见的方法,包括继承的方法
  • getMethod(方法名,参数类型列表)
  • getDeclaredMethods()//获得本类定义的方法,包括私有,不包括继承的方法
  • getDeclaredMethod(方法名, int.class, String.class)

反射新建实例

  • newInstance();//执行无参构造
  • newInstance(6, “abc”);//执行有参构造
  • getConstructor(int.class, String.class); //执行含参构造,获取构造方法

反射调用成员变量

  • getDeclaredField(变量名); //获取变量
  • setAccessible(true); //使私有成员允许访问
  • set(实例, 值); //为指定实例的变量赋值,静态变量,第一参数给 null
  • get(实例); //访问指定实例的变量的值,静态变量,第一参数给 null

反射调用成员方法

  • 获取方法
  • Method m = c.getDeclaredMethod(方法名, 参数类型列表);
  • m.setAccessible(true) ;//使私有方法允许被调用
  • m.invoke(实例, 参数数据) ;//让指定的实例来执行该方法

反射的应用

创建类

class Student{
    String name="jack";
    int age=20;    
    public Student() {
       System.out.println("无参构造");
    }
    public Student(String name) {
       this.name=name;
       System.out.println("含参构造"+name);
    }    
    public void show(int a) {
       System.out.println("show()..."+a);
    }    
}

获取类对象

private static void method() throws Exception {
   Class clazz = Student.class;
   Class<?> clazz2 = Class.forName("seday15.Student");
   Class clazz3 = new Student().getClass();       
   System.out.println(clazz.getName());
   System.out.println(clazz2.getName());
   System.out.println(clazz3.getName());
}

获取构造方法

private static void method3(Class clazz) {
       Constructor[] cs = clazz.getDeclaredConstructors();
       for (Constructor c : cs) {
           String name = clazz.getSimpleName();
           System.out.println(name);           
           Class[] cs2 = c.getParameterTypes();//参数
           System.out.println(Arrays.toString(cs2));           
       }
 }

获取成员方法

private static void method4(Class clazz) {
     Method[] ms = clazz.getMethods();
       for (Method m : ms) {
           String name = m.getName();
           System.out.println(name);           
           Class<?>[] cs = m.getParameterTypes();
           System.out.println(Arrays.toString(cs));
       }
}

获取成员变量

  private static void method2(Class clazz) {
       Field[] fs = clazz.getFields();//获取public的属性
       for (Field f : fs) {
           String name = f.getName();
           String tname = f.getType().getSimpleName();
           System.out.println(name);
           System.out.println(tname);
       }
}

我们再来说说暴力反射,什么是暴力反射呢?Java中有许多的方法和对象为了安全考虑,都被封装在类中。通常这些私有的方法和对象都只能在该类的内部进行调用,对于外部的类来说,都是隐藏、不可见的。为了能够在外部类中获取和操作这些私有的对象和方法,就可以使用暴力反射的方式来实现。简单来讲就是指可以将程序中的私有的属性或者方法通过反射技术,暴力的获取到资源。

创建Person类

class Person{    
    private String name="jack";
    private int age = 30;    
    private void show(int[] a) {
       System.out.println("show()..."+Arrays.toString(a));
    }
    private void test() {
       System.out.println("test()...");
    }
}

看以上这个例子,成员变量和成员方法都是私有的,那么我们将如何获取它的值呢?我们来测试一下

package seday16new;

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

public class ReflectPerson {
    public static void main(String[] args) throws Exception {
       Class<?> clazz = Class.forName("seday16new.Person");
//     method(clazz);//隐私属性
       method2(clazz);//执行方法
    }
    
    private static void method2(Class<?> clazz) throws Exception {
       Method m = clazz.getDeclaredMethod("show", int[].class);
       Object obj = clazz.newInstance();
       m.setAccessible(true);//方法隐私可见
       m.invoke(obj, new int[]{1,2,3});//执行
    } 
    
    private static void method(Class clazz) throws Exception {
       Field f = clazz.getDeclaredField("name");
       System.out.println(f.getType().getName());
       f.setAccessible(true);//属性隐私可见
       Object obj = clazz.newInstance();
//     f.set(obj, "rose");//设置值
       System.out.println(f.get(obj));//获取值   
              
       //---所有属性
       Field[] fs = clazz.getDeclaredFields();
       for (Field ff : fs) {
           System.out.println(ff);
           ff.setAccessible(true);//暴力反射
           System.out.println(ff.get(obj));
       }       
    }    
}

结果:

  • 获取私有属性值并修改
  • 获取私有方法并执行

你可能感兴趣的:(java学习,反射)