浅谈Java的反射的原理
Java的编译过程
谈及反射,不得不先了解一下,java的整个编译过程,整体的java编译过程可以参考 之前的一篇 一个java文件被执行的历程
这里我们只针对 对象这一层级来讨论,一个java文件,我们经过编译,会得出 一个 字节码文件(.class),这时候,进入解释阶段,编译器会将这个.class加载进内存中,此时,它首先会生成一个 Class对象。
Class对象与对象形成的过程
Class对象
在java世界里,一切皆对象。从某种意义上来说,java有两种对象:实例对象和Class对象。对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。
- Class 对象只能由系统建立对象
- 一个类在 JVM 中只会有一个Class实例
- –每个类的实例都会记得自己是由哪个 Class 实例所生成
class对象包含的信息有:
- 数据成员名
- 内部方法
- 构造方法
- 集成自哪个接口、类
对象的形成过程
我们的实例对象是通过Class对象来创建的。

每一个类都有一个Class对象,每当编译一个新类就产生一个Class对象,基本类型 (boolean, byte, char, short, int, long, float, and double)有Class对象,数组有Class对象,就连关键字void也有Class对象(void.class)。Class对象对应着java.lang.Class类,如果说类是对象抽象和集合的话,那么Class类就是对类的抽象和集合。
Class类没有公共的构造方法,Class对象是在类加载的时候由Java虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。
在类加载阶段,类加载器首先检查这个类的Class对象是否已经被加载。如果尚未加载,默认的类加载器就会根据类的全限定名查找.class文件。在这个类的字节码被加载时,它们会接受验证,以确保其没有被破坏,并且不包含不良java代码。一旦某个类的Class对象被载入内存,我们就可以它来创建这个类的所有对象。
反射的本质及应用
上面的基础了解完毕,我们进入今天的主体,何为反射。
所谓反射,官方的定义是: 指计算机程序在运行时(runtime) 可以访问、检测和修改它本身状态或行为的一种能力。通俗说,反射就是程序在运行的时候能够“观察”并且修改自己的行为,是程序对自身的反思、自检、修改。
理解反射,首先得知道它的对立面,“正射”
“正射”
前面说到了Class对象,每个类的运行时的类型信息就是用Class对象表示的。系统会自动创建唯一一个Class对象,它包含了与类有关的信息。此时的java文件(一个类)处于一个中间状态,并不是我们使用的对象,只有当我们使用 “ new Object()”时,才会在JVM堆中根据这个Class对象来产生真正供我们使用的实例对象。其实也就是上面部分的对象的形成过程。
正射的使用意义是,我事先定义了一个对象的某些东西,然后当我需要的时候,我会通知内存去创建这个对象,然后我事先知道这个对象有什么,所以我会精准的调用它的某个方法,某个成员变量。
用一个我们习以为常的demo来举一下例:
class Human {
String name;
int age;
String nation;
Human(String name,int age,String nation) {
this.name=name;
this.age=age;
this.nation=nation;
}
void changeName(String name){
this.name=name;
}
}
public class Main {
public static void main(String[] args){
Human human=new Human("张三",22,"中国");
human.changeName("李四");
}
}
在上面Main类的main方法中,我之所以可以写human.changeName(“张三”) 是因为Human类也是我自己写的,我清楚的知道,human作为Human的实例对象,可以调用changeName方法,如果我手抖写了调用changeNamee方法,我也会立即改回来,因为我知道Human里没有这个方法。假如我不知道Human里有没有一个改名字的方法,即Human类对我来说是不透明的第三方类,我尝试性的在程序中调用了一个newName方法,保存、编译。这时候编译器会通知我,这样写程序是不对的,Human里没有一个叫newName的方法,编译失败。
反射
假如此时我只想使用对象某一个方法,某一个成员变量,而不想用其他的部分,这时候如果用“正射”(走正常的对象创建过程,new一下),就会被迫创建一个完整的该对象(有一说一,有点浪费),此时我可以根据类的全路径+名称,去内存中拿出这个类的Class对象,根据这个Class对象,灵活的去获取这个类片面的信息。这种在运行时访问、修改对象的状态和行为,可以给程序带来极大的灵活性。这便是反射
反射可提供的功能
在运行时判断任意一个对象所属的类。
在运行时构造任意一个类的对象。
在运行时判断任意一个类所具有的成员变量和方法。
在运行时调用任意一个对象的方法。
生成动态代理。
详细的API使用,可以查阅java的官方文档。
反射的使用
使用Java注解配合反射可以开发出各种工具、框架。例如,Spring中的注解、工厂模式中创建对象的方式等
这里实现一个用自定义注解 @AutoField 实现为属性赋值。
定义注解@AutoField
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoField {
String value() default "";
}
编写解析类。BeanFactory中的createBean方法通过反射拿到注解 @AutoField的值并赋给对象。
public class BeanFactory {
public static <T> T createBean(Class<T> clazz) {
T o = null;
try {
o = clazz.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
if (declaredField.isAnnotationPresent(AutoField.class)) {
AutoField AutoField = declaredField.getAnnotation(AutoField.class);
if (!declaredField.isAccessible())
declaredField.setAccessible(true);
try {
if (declaredField.getType().getSimpleName().equals("String"))
declaredField.set(o, AutoField.value());
else if (declaredField.getType().getSimpleName().equals("byte"))
declaredField.set(o, Byte.parseByte(AutoField.value()));
else if (declaredField.getType().getSimpleName().equals("short"))
declaredField.set(o, Short.parseShort(AutoField.value()));
else if (declaredField.getType().getSimpleName().equals("int"))
declaredField.set(o, Integer.parseInt(AutoField.value()));
else if (declaredField.getType().getSimpleName().equals("long"))
declaredField.set(o, Long.parseLong(AutoField.value()));
else if (declaredField.getType().getSimpleName().equals("float"))
declaredField.set(o, Float.parseFloat(AutoField.value()));
else if (declaredField.getType().getSimpleName().equals("double"))
declaredField.set(o, Double.parseDouble(AutoField.value()));
else if (declaredField.getType().getSimpleName().equals("long"))
declaredField.set(o, Long.parseLong(AutoField.value()));
else if (declaredField.getType().getSimpleName().equals("boolean"))
declaredField.set(o, Boolean.parseBoolean(AutoField.value()));
else
throw new RuntimeException(declaredField.getName() + " of " + clazz.getName() + " is not a value field");
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
return o;
}
}
定义实体类
public class Teacher {
@AutoField("12223")
private int id;
@AutoField("Zhang")
private String name;
@AutoField("20")
private int age;
@AutoField("false")
private boolean isProfessor;
@AutoField("G")
private String sex;
@AutoField("CQU")
private String school;
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public boolean isProfessor() {
return isProfessor;
}
public String getSex() {
return sex;
}
public String getSchool() {
return school;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setProfessor(boolean professor) {
isProfessor = professor;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setSchool(String school) {
this.school = school;
}
@Override
public String toString() {
return "Teacher{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", isProfessor=" + isProfessor +
", sex=" + sex +
", school='" + school + '\'' +
'}';
}
}
测试
public class Main {
public static void main(String[] args) {
Teacher teacher = BeanFactory.createBean(Teacher.class);
System.out.println(teacher);
}
浅谈Java的反射的原理的更多相关文章
- 浅谈Java的反射机制和作用
浅谈Java的反射机制和作用 作者:Java大师 欢迎转载,转载请注明出处 很多刚学Java反射的同学可能对反射技术一头雾水,为什么要学习反射,学习反射有什么作用,不用反射,通过new也能创建用户对象 ...
- 浅谈Java之反射
反射 四种获取Class实例的方法 定义测试结构 获取属性结构 获取方法结构 获取构造器结构(包括父类泛型) 获取实现的接口 获取所在包 获取注解 获取并创建指定构造器 获取指定属性 获取并运行指定方 ...
- 浅谈Java代理二:Cglib动态代理-MethodInterceptor
浅谈Java代理二:Cglib动态代理-MethodInterceptor CGLib动态代理特点: 使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生 ...
- !! 浅谈Java学习方法和后期面试技巧
浅谈Java学习方法和后期面试技巧 昨天查看3303回复33 部落用户大酋长 下面简单列举一下大家学习java的一个系统知识点的一些介绍 一.java基础部分:java基础的时候,有些知识点是非常重要 ...
- 浅谈java类集框架和数据结构(2)
继续上一篇浅谈java类集框架和数据结构(1)的内容 上一篇博文简介了java类集框架几大常见集合框架,这一篇博文主要分析一些接口特性以及性能优化. 一:List接口 List是最常见的数据结构了,主 ...
- 浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance
浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance java.lang.reflect.Proxy:该类用于动态生成代理类,只需传入目标接口.目标接口的类加载器以及Inv ...
- 浅谈Java回收对象的标记和对象的二次标记过程_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 一.对象的标记 1.什么是标记?怎么标记? 第一个问题相信大家都知道,标记就是对一些已死的对象打上记号,方便垃圾收集器的 ...
- 龙生九子-浅谈Java的继承
龙生九子-浅谈Java的继承 书接上回,我们之前谈过了类和对象的概念,今天我来讲一讲面向对象程序设计的另外一个基本概念-继承 目录 为什么需要继承 自动转型与强制转型 继承能干啥 复写和隐藏 supe ...
- 浅谈Java的throw与throws
转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...
随机推荐
- Linux 网络协议栈开发基础篇—— 网桥br0
一.桥接的概念 简单来说,桥接就是把一台机器上的若干个网络接口"连接"起来.其结果是,其中一个网口收到的报文会被复制给其他网口并发送出去.以使得网口之间的报文能够互相转发. 交换机 ...
- IFIX 数据源 节点 标签 域名
一个动画,前景颜色 数据源如上图 点 ,,, 进入选择界面,如下 Fix32 应该是统一的前缀,自动添加上的 然后就是我们的节点名字,启动ifix的时候显示的那个节点名字 标签应该就是我们的 变量/ ...
- Gym 101170I Iron and Coal(BFS + 思维)题解
题意:有一个有向图,有些点是煤,有些点是铁,但不会同时有铁和煤.现在我要从1出发,占领可以到达的点.问最少占领几个点能同时拥有一个煤和一个铁(1不用占领). 思路:思路很秀啊.我们从1往外bfs,得到 ...
- 关于谷歌浏览器不支持html5中audio的autoplay解决方法(js代码解决)
当我们直接写autoplay时,在chrome中浏览器并没有自动播放音频: 如果直接通过js来调用audio的play()方法也不行: 控制台还会报错 大概意思:play()调用失败,因为用户没有与文 ...
- Apple Watch Series 6 编织表带如何清洗
Apple Watch Series 6 编织表带如何清洗 如何清洁 Apple Watch https://support.apple.com/zh-cn/HT204522 refs xgqfrms ...
- H5 CSS 悬浮滚动条
H5 CSS 悬浮滚动条 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!
- Node.js 返回 JSON 数据
Node.js 返回 JSON 数据 request.end([data[, encoding]][, callback]) var http = require('http'); const log ...
- Android Webview & iframe auto full screen
Android Webview & iframe auto full screen android webview iframe 全屏适配 https://stackoverflow.com/ ...
- back to top & back to bottom
back to top & back to bottom infinite auto load more & infinite scroll & load more https ...
- BGV作为拥抱新时代的DeFi项目,是否有能力超越YFI?
随着今年11月DeFi蓝筹股们的集体反弹,市场变化让投资者明白,不能再死守诸如COMP和MKR的古典DeFi了,只有拥抱新时代的DeFi们才有赚钱的可能,不要和钱过不去.经过9-10月的回调,11月的 ...