反射详解
Posted Firm陈
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反射详解相关的知识,希望对你有一定的参考价值。
反射是框架设计的灵魂
使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)
一.反射概述
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
实际上,我们创建的每一个类也都是对象,即类本身是java.lang.Class类的实例对象。这个实例对象称之为类对象,也就是Class对象。那么,Class对象又是什么对象呢?
二.Class类对象
下图是Class类的api
从图中可以得出以下几点:
1.Class 类的实例对象表示正在运行的 Java 应用程序中的类和接口。也就是jvm中有很多的实例,每个类都有唯一的Class对象。
2.Class 类没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机自动构造的。也就是说我们不需要创建,JVM已经帮我们创建了。
3.Class 对象用于提供类本身的信息,比如有几种构造方法, 有多少属性,有哪些普通方法
三.反射的原理
反射首先是能够获取到Java中的反射类的字节码,然后将字节码中的方法,变量,构造函数等映射成 相应的 Method、Filed、Constructor 等类。
四.反射的应用
取出类的modifiers,数据成员,方法,构造器,和超类
找出某个接口里定义的常量和方法说明.
取得和设定对象数据成员的值,如果数据成员名是运行时刻确定的也能做到.
在运行时刻调用动态对象的方法.
1.类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实
现对这个类进行初始化。
(1)加载 就是指将 class 文件读入内存,并为之创建一个 Class 对象。 任何类被使用时系统都会建立一个 Class 对象
(2)连接 验证 是否有正确的内部结构,并和其他类协调一致 准备 负责为类的静态成员分配内存,并设置默认初始化值 解析 将类的二进制数据中的符号引用替换为直接引用
(3)初始化
2.类的初始化
(1)创建类的实例
(2)类的静态变量,或者为静态变量赋值
(3)类的静态方法
(4)使用反射方式来强制创建某个类或接口对应的 java.lang.Class 对象
(5)初始化某个类的子类
3.获取类对象有3种方式
(1)Class.forName()(常用)
(2)Hero.class
(3)new Hero().getClass()
在一个JVM中,一种类,只会有一个类对象存在。所以以上三种方式取出来的类对象,都是一样。(此处准确是在ClassLoader下,只有一个类对象)
package pojo;
public class ObjectTest {
public static void main(String[] args) {
String className = "pogo.Hero";
try {
//获取类对象的第一种方式
Class pClass1 = Class.forName(className);
//获取类对象的第二种方式
Class pClass2 = Hero.class;
//获取类对象的第三种方式
Class pClass3 = new Hero().getClass();
System.out.println(pClass1==pClass2);//输出true
System.out.println(pClass1==pClass3);//输出true
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
三种方式中,常用第一种,第二种需要导入类的包,依赖太强,不导包就抛编译错误。第三种对象都有了还要反射干什么。一般都第一种,一个字符串可以传入也可写在配置文件中等多种方法。
四.反射的简单使用
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@Data
@AllArgsConstructor
@Slf4j
public class People {
public String name;
private Integer age;
private void show(){
log.info("name:"+this.name+" age:"+this.age);
}
}
这里图方便使用的Lombok(很好用的一款工具)建立一个People类,类里面有私有属性、公有属性、私有方法等。
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 通过反射调用方法和属性
*
*/
@Slf4j
public class Reflection {
public static void main(String[] args) {
try {
Class<People> clazz = People.class;
//使用反射建立对象
Constructor<People> constructor = clazz.getConstructor(String.class, Integer.class);
People people = constructor.newInstance("Tom", 12);
log.info(people.toString());
//访问类的公共属性
Field name = clazz.getDeclaredField("name");
name.set(people, "Jerry");
log.info(people.toString());
//访问类的私有属性
Field age = clazz.getDeclaredField("age");
age.setAccessible(true);
age.set(people, 20);
log.info(people.toString());
//访问类的公共方法
Method getName = clazz.getDeclaredMethod("getName");
log.info(""+getName.invoke(people));
//访问类的私有方法
Method show = clazz.getDeclaredMethod("show");
show.setAccessible(true);
show.invoke(people);
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchFieldException e) {
e.printStackTrace();
}
}
}
日志打印结果如下
以上是关于反射详解的主要内容,如果未能解决你的问题,请参考以下文章