JAVA 反射的应用还是比较多,这里会对反射的一些原理进行介绍,然后我们才知道如何使用和优化。至于反射的使用介绍,这里就不在过多叙述了,API 上都介绍得有。
要了解JAVA 反射的原理,我们还得对类在虚拟机中的一些知识做简要介绍...
一、类文件的结构:
1.1 虚拟机加载Class文件过程:
在JVM 类加载机制的博客里面我介绍过整体流程,这里仅仅介绍加载时相关部分。
在我们启动一个类,或者其他方式加载一个类的时候,会通过类的全限定名获取该类的二进制流,然后将字节流所代表的的静态存储结构转化成方法区的运行时数据结构,然后会生成一个代表该类的java.lang.Class 对象,作为在方法区这个类的访问入口。也就是说只要完成了这一步骤,那么通过这个入
口我们就可以访问里面的存储好的数据结构信息了。而且动态加载的时候,会先进行查找,该类是否存在,
存在了就不会再加载了,保持一份。
class 文件是一组以8位字节为基础单位的二进制流,各个数据项目按严格的顺序紧凑的排列在Class文
件中,里面的信息主要描述以下信息:
1.版本号:主版本号和次版本号
2.常量池:主要存放字面量(Literal)和符号引用(references)
2.1 字面量:文本字符串、final 类型的常量值 等
2.2 符号引用:
a.类和接口的全限定名字
b.字段描述和描述符
c.方法的名称和描述
3.访问标志:
a.是类还是接口
b.是否是public 等类型
c.是否是abstract ,是否被声明为final 等标志
4.类索引、父类索引和接口索引集合
a.类索引:确定这个类的全限定名
b.父类索引:确定父类的全限定名
c.接口索引集合:作为入口,作为一个计数器
5.字段表集合:
包括信息有字段作用域(public,private等修饰符)、是实例变量还是类变量(static)、可变性 (final)、并发可见性(volatile)、可否被序列化(transient)等信息
6.方法集合:
包括访问标志、名称索引、描述符索引、属性表集合。
7.其他:包括属性表集合、Code 属性(指令) 等其他这里暂时不过多介绍,详细请看虚拟机的书籍。
二、反射概念:
通过上面简单的介绍,相信大家了解了我们的Class 文件在加载到JVM 里面之后,实际存放的信息有很
多,而且上面介绍的都是大家有一定了解的,比如 方法 、属性 等等,那么反射是什么呢?
所谓反射是JAVA 语言允许在 运行时拥有一种自审的能力,也就是说JVM 允许代码在运行期间可以获得
类的内部信息,简单的说我们可以在程序运行期间获得刚才我们介绍的类里面的信息。
2.1 反射的常用方法:
a.forName(String className) :
返回与带有给定字符串名的类或接口相关联的 Class 对象。
b.forName(String name, boolean initialize, ClassLoader loader) :
使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的 Class 对象。
c.getAnnotation(Class<A> annotationClass)
如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
d.getAnnotations()
返回此元素上存在的所有注释。
e.getConstructor(Class<?>... parameterTypes)
返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
f.getDeclaredField(String name)
返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
g.getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
这里我就不累赘了,仅仅引入性的介绍几个,更多的可以去看看API
三、反射的基本使用:这里我们写一个简单类,模拟常见的功能。
public class Test {
// 构造方法
public Test() {
System.out.println("无参数构造");
}
public Test(String str) {
System.out.println("有参构造:"+str);
}
public void test(){
System.out.println("普通测试方法:");
}
public static void staticTest(){
System.out.println("静态测试方法");
}
// 基本属性
private Integer number;
public String name = "张三";
}
1.类加载:
public static void main(String[] args) throws Exception {
Class<?> c = Class.forName("com.Test");
// 这里加载类,会调toString 方法, 打印类型,和getName 方法
// 同时发现类已经存在,说明加载成功
// 这里常常我们用来动态加载一个类,比如再获得JDBC 连接的时候,
// 我们可以动态的获得不通厂商的连接:Class.forName("xxx.oracle/mysql")
System.out.println("类信息:"+c);
// 同时这里可以直接这只加载器实现:Class.forName(name, initialize, loader)
}
2 获得方法并且调用:
public static void main(String[] args) throws Exception {
Class<?> c = Class.forName("com.Test");
// 这个是获得指定方法,我们先获得普通方法
Method m = c.getMethod("test");
// 这里执行会失败了,因为我们们的类没进行实例化
// m.invoke(c);
// 这样就不会,这里使用了默认的构造
m.invoke(c.newInstance());
// 但是静态方法不用实例化就可以
Method m2 = c.getMethod("staticTest");
m2.invoke(c);
// 当然我们还能获得所有的方法信息
// 获得该类所有方法
c.getDeclaredMethods();
// 获得包括继承的类的所有方法
c.getMethods();
}
3.获得字段信息:
public static void main(String[] args) throws Exception {
Class<?> c = Class.forName("com.Test");
// 私有字段是无法通过公有方式访问
// Field f1 = c.getField("number");
// public 字段是可以直接访问
Field f = c.getField("name");
System.out.println(f);
// 这是赋值,必须先获得对象实例,可以为字段赋值
Object o = c.newInstance();
f.set(o, "2");
System.out.println(f.get(o));
// 其他方法,和获取method 差不多
}
关于构造器,权限等这些就可以看API,这里仅仅介绍。
4.其他应用:
反射运用得很多,比如我们熟悉的hibernate、spring、以及其他的orm 框架都需要用到。
这里我们模拟hibernate 的实现,来完成对象的保存操作。
// 这是我们模拟的实体bean
// 这是我们模拟的实体bean
public class Bean {
private Integer id;
private String name;
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
import java.lang.reflect.Field;
import java.lang.reflect.Method;
// 这是我们的测试
public class Test {
public static void main(String[] args) {
// 1. 首先我们创建一个bean,模拟从前端获取的数据
Test t = new Test();
Bean bean = t.getBean();
// 2.生成我们需要的SQL 并设值
t.save(bean);
}
private Bean getBean(){
// 模拟用反射实现
Bean bean = null;
try {
Class c = Class.forName("Bean");
bean = (Bean) c.newInstance();
// 私有字段无法访问,我们通过方法赋值
Method m1 = c.getDeclaredMethod("setId",Integer.class);
Method m2 = c.getDeclaredMethod("setName",String.class);
Method m3 = c.getDeclaredMethod("setPassword",String.class);
m1.invoke(bean, 1);
m2.invoke(bean, "admin");
m3.invoke(bean, "123456");
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}
// 假设我们的表 就是 BEAN
private void save(Bean bean){
Field[] fields = Bean.class.getDeclaredFields();
StringBuffer sb = new StringBuffer("INSERT INTO BEAN VALUES");
sb.append(getInsertStr(fields.length));
// 这里我们可以看到SQL 已经生成
System.out.println(sb);
// 这里就是我们的JDBC 根据字段名字赋值 的操作了。
// 当然hibernate 写得肯定会复杂很多,但是基本原理不变
}
private String getInsertStr(int fields){
StringBuffer sb = new StringBuffer("(");
for(int i = 0;i<fields;i++){
sb.append("?,");
}
sb.delete(sb.length()-1,sb.length());
sb.append(")");
return sb.toString();
}
}
在spring 里面,在介绍过生成代理类,也就是AOP 的地方也用过,这里也就不多说了。
小结:
1.这里介绍了反射的基本运用,以及一些相关原理的东西,还没真正深入
2.反射给了我们很大的灵活,但是同时很多错误只能到运行期间才能发现,使用要多注意。
3.反射提供灵活的同时,也牺牲了性能,在JDK1.6+ 版本,反射的一般调用,比直接调用慢2倍左右。
性能这一块后面再研究,再招优化的方案。
文章转自
http://greemranqq.iteye.com/blog/2023781
分享到:
相关推荐
### Java反射机制详解 #### 一、引言 在Java面试中,经常会出现与反射...以上内容不仅解释了Java反射机制的相关知识点,还通过示例代码进行了实践演示,希望能够帮助你在Java面试中更好地理解和运用这一重要特性。
3. **掌握动态获取对象、设置属性和调用方法的步骤**:熟练运用配置文件和反射机制来动态获取对象实例、设置对象属性以及调用对象的方法。 4. **熟悉文件输入输出流的基本使用方法**:掌握如何使用Java中的文件输入...
在标题"jdk反射机制资料大合集"中,我们可以理解这是一份包含多本书籍的资源包,专门针对Java反射机制进行深入讲解,包括中英文版本,旨在帮助开发者更好地理解和运用这一技术。 描述中提到,这个资料包包含了8本书...
这篇文档主要探讨了TD-SCDMA系统的无线传播环境、基本原理、关键技术和参数特点。 无线传播环境在移动通信系统中扮演着至关重要的角色。无线移动信道是指基站天线与移动终端天线之间信号传播的路径,它包括直射、...
反射机制在Java编程语言中是一项强大的工具,它允许程序在运行时检查并操作类、接口、字段和方法等对象。这个技术的核心概念是能够在运行时分析类的信息,并且能够动态地创建对象、调用方法以及访问和修改字段值。...
反射(Reflection)是Java提供的一种强大的机制,允许程序在运行时检查类、接口、字段和方法的信息,甚至动态调用方法和修改字段值。通过java.lang.Class类和相关的API,我们可以获取类的结构,创建对象,访问和修改...
Java反射是Java编程语言中的一个强大特性,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。...理解并熟练运用反射原理,能够帮助开发者更好地理解和控制Java程序的运行行为。
在理解了反射的基本原理和用法后,开发者可以灵活应对各种复杂场景,如动态加载类、处理未知类型数据、实现插件化等。在Spring等框架中,反射更是发挥了不可或缺的作用。希望这个简单的反射例子能帮助你更好地理解和...
【GPS基本原理及其Matlab仿真图文】是一份深入讲解全球定位系统(GPS)工作原理及其在Matlab环境下的仿真实现的课件。本课件旨在帮助学习者理解GPS信号的特点、传播方式以及如何通过仿真工具进行信号分析与处理。 ...
1. 基本概念:反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射...
两级反射汇聚式太阳能焊机的设计概念是基于光学反射原理,它由两部分组成:初级反射器和次级反射器。初级反射器通常是一个大的聚光镜或反射镜阵列,负责收集并集中大量的太阳光;次级反射器则进一步聚焦这些光线,使...
本文将深入探讨Hibernate如何运用反射原理,以及其在简化数据库操作中的应用。 首先,我们需要理解反射的基本概念。在Java中,反射是一种在运行时分析类和对象的能力,允许程序动态地获取类的信息(如类名、方法名...
本文将深入探讨这一设备的工作原理、应用范围以及它在行业分类中的位置。 SL-TDR是一种用于检测和分析传输线(如电缆、光纤等)性能的仪器。它的核心功能是通过发送脉冲信号到传输线,并测量返回的反射,以确定线路...
3. 使用反射增强灵活性:利用反射机制,使得框架可以动态地发现和操作类,提高其适应性和扩展性。 4. 提供API和配置:提供用户友好的API接口,以及配置文件或注解,让开发者可以方便地使用框架。 5. 测试与优化:...
Java的类加载机制遵循“双亲委派模型”,这意味着当一个类加载器收到加载类的请求时,它会先委托给父类加载器,只有当父类加载器无法找到该类时,子类加载器才会尝试自己去加载。这种设计保证了核心库的稳定性和安全...
- 学习接近开关和红外反射传感器的工作原理。 - 实现目标距离的检测。 - 探讨传感器在自动控制中的应用。 - **关键知识点**: - 接近开关的工作原理。 - 红外反射传感器的工作原理。 - 自动控制系统设计。 ##...
- 压力感受性反射、心肺感受器反射和化学感受性反射; - 血管活性物质的作用机制:肾素-血管紧张素系统、肾上腺素和去甲肾上腺素、血管升压素、内皮生成的血管活性物质; - 动脉血压调节机制; - 冠状循环和脑...
这一季不仅深入讲解了Java 8新增加的Lambda表达式等特性,还覆盖了一系列重要的Java编程概念和技术,如异常处理、泛型、反射、AOP(面向切面编程)、枚举、注解、线程管理和垃圾回收机制等。通过这些课程的学习,...
虽然实际的ORM框架如NHibernate、Entity Framework等提供了更复杂的功能和优化,但这个示例为我们理解ORM和反射的工作原理提供了很好的起点。在实际项目中,可以根据需求选择合适的ORM解决方案,以提高开发效率和...