8-java反射-基础反射知识

java反射-基础反射知识


反射

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

主要用在企业级框架底层,可以动态根据 IO 读到的一些类、接口、枚举、注解等的信息,进而让其中的成员变量、方法、构造方法运行起来

  • 目的:不使用 new 关键字创建对象,还能让其中的变量、方法执行
  • 核心:1. 获取到某个 class 文件;2. 动态分析 class 中的内容

1. 反射示意图

任何 class文件 都是一个个体。
以下图为例,我们写了几个自定义类,它们编译后生成的 class文件, 本质上都是 Class类的一个实例
也即如果程序中可得到 Class对象,也即一定获取到一个具体的 class文件。

这也是 java OO思想的体现,任何事物都是一个对象,包括编译生成的 class文件

javac编译
javac编译
javac编译
抽象为
封装描述
Person.java
Person.class
Student.java
Student.class
Teacher.java
Teacher.class
这类事物
Class类

2. 获取 Class对象 的方法

2.1 getClass方法

在 Object类 中定义了getClass方法。

Person p = new Person();
Class clazz = p.getClass();// class reflection.Person

int[] arr = new int[3];
Class clazz2 = arr.getClass();// class [I

2.2 class属性

任何类型,java 均配了一个class属性

Class clazz = Person.class;// class reflection.Person

Class clazz2 = int[].class;// class [I

2.3 forName方法

常用方法,前两种方法实际上已经知道是什么类了,有些多此一举。使用 Class类 的静态方法可以得到 Class对象

Class.forName("com.mysql.jdbc.Driver")获取到Driver的class类对象,参数必须写全路径。

3. CLass对象的创建时间

Class对象(.class文件) 是 JVM 将 class文件加载至方法区时,会自动在中创建出当前这个class文件对应的唯一对象,实际上 new对象时,不是通过方法区的class文件创建的,而是根据堆中这个 class对象创建的。

4. 使用Class对象创建类的对象

newInstance方法要求被反射的class文件中,一定有默认的公开构造,即无参数公开构造

CLass clazz = CLass.forName("reflection.Person");
Object obj = clazz.newInstance();// 注意该方法在JDK9后弃用
// newInstance方法要求被反射的class文件中,一定有默认的公开构造,即无参数公开构造
System.out.println(obj);//reflection.Person@6833ce2c

但是 newInstance 方法只能构造公开无参的,不方便,所以还是获取到其中的构造方法,再去使用会更加方便

5. 获取CLass对象的内容

对于一个类而言,重要的就是 成员变量、构造方法、成员方法。反射解析出这些成员后,再封装成不同的对象。

  • 成员变量: Field
  • 构造方法: Constructor
  • 成员方法: Method

以Person为例来获取其中内容

public class Person {
    private int id;
    public String name;
    public Person(){

    }
    public Person(int id){
        this.id = id;
    }
    private Person(int id, String name){
        this.id = id;
        this.name = name;
    }
    private void say(){
        System.out.println("say");
    }
    public int hi(String name){
        System.out.println("hi" + name);
        return 0;
    }
}

5.1 获取构造方法

getConstructor(参数类型)获取某个特定的构造函数

Class clazz = Class.forName("reflection.Person");
Constructor cons = clazz.getConstructor(int.class);
System.out.println(cons); // public reflection.Person(int)
Object obj = cons.newInstance(123);
// obj就是创建的Person对象,依据的构造是仅有一个int参数的构造

getConstructores()获取所有的公开的构造方法

Class clazz = Class.forName("reflection.Person");
Constructor[] cons = clazz.getConstructors(int.class);
for(Constructor c:cons){
    System.out.println(c);
}
/*
---------------演示getConstructors--------------
public reflection.Person(int)
public reflection.Person()
*/

getDeclaredConstructor()获取所有构造函数,包括私有构造。仅仅获取私有构造是不能用的,必须修改权限。Constructor继承了AccessibleObject,可以修改权限。

Class clazz = Class.forName("reflection.Person");
Constructor cons = clazz.getDeclaredConstructor(int.class, String.class);
cons.setAccessible(true); // 修改权限
System.out.println(cons); // private reflection.Person(int,java.lang.String)
Object obj1 = cons.newInstance(123, "321");
System.out.println(obj1); // reflection.Person@6833ce2c
面试小技巧

面试如果问到 private、public等的时候,说private是私有的,不能让外界访问的,可以说但是通过反射技术可以取消访问控制,然后将话题转向反射

5.2 获取成员变量

使用的场景较少, 使用 getField 获取成员变量,然后利用 set 方法设置某个对象该成员变量的值, 也可以利用 get 方法获取值

小细节如果是静态成员变量,那么传入的参数是null就可以正常获取了

Field field = clazz.getField("name");
field.set(obj, "jack");
System.out.println(obj); // reflection.Person@2aaf7cc2
System.out.println(field.get(obj));// jack

5.3 获取方法

  • getMethod:获取特定方法,
  • getDeclaredMethod:获取包含私有的方法,使用时需要取消权限检查
  • getMethods:获取所有public方法,包含它所有父类的方法
  • getDeclaredMethods: 获取当前类的所有方法,含私有,不含父类的
  • 如果反射静态方法,传入的对象写为null即可
Class clazz = Class.forName("...");
// 依靠方法名与参数列表来反射方法
Method method = clazz.getMethod("say", String.class);
Object obj = clazz.newInstance();
// invoke方法是是method方法运行,参数:运行该方法的对象,该方法的参数,返回值:被反射的方法的返回值
Object ret = method.invoke(obj);

Method method = clazz.getMethod("hi", null);
method.setAccessible(true);
method.invoke(obj);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值