要了解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 对象所表示的类或接口的指定已声明方法。
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 差不多 }
4.其他应用:
反射运用得很多,比如我们熟悉的hibernate、spring、以及其他的orm 框架都需要用到。
// 这是我们模拟的实体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; } }
// 这是我们模拟的实体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; } }
小结:
1.这里介绍了反射的基本运用,以及一些相关原理的东西,还没真正深入
2.反射给了我们很大的灵活,但是同时很多错误只能到运行期间才能发现,使用要多注意。
3.反射提供灵活的同时,也牺牲了性能,在JDK1.6+ 版本,反射的一般调用,比直接调用慢2倍左右。
性能这一块后面再研究,再招优化的方案。
原文出处:http://qindongliang.iteye.com/blog/2023916
相关推荐
通过本文的学习,我们深入了解了Java反射机制的基本概念、原理以及应用。Java反射机制为Java程序提供了一种强大的动态处理能力,使得Java不仅仅局限于静态类型语言的功能限制。掌握Java反射机制对于开发者来说是非常...
### Java反射机制概述 Java反射机制是指Java程序在运行时,可以动态地获取一个类的信息以及调用其方法的机制。这是Java语言的一个重要特性,允许程序在运行时检查和修改类的行为。 #### 反射机制的基本操作 在...
#### 一、Java反射机制概述 Java反射机制是Java语言的一个重要特性,它允许程序在运行时获取类的信息并操作对象。Java反射机制的主要作用包括:获取类的所有属性和方法、构造动态实例、调用类的方法等。通过反射,...
Java反射机制是Java编程语言中的一个强大特性,它允许程序在运行时检查和操作类、接口、对象以及它们的方法和字段。通过反射,开发者可以实现动态类型检查、元编程、插件系统等功能,大大增强了代码的灵活性和可扩展...
#### 二、Java反射机制概述 在Java中,反射机制是一种非常重要的特性,它使得程序能够在运行时动态地获取类的内部信息,如类名、构造器、成员变量和方法等,并且能够直接操作这些内部结构。通过这种方式,Java反射...
ava反射机制 概述:通俗地讲Java反射就是通过类名获得类的实例的方法。java.lang.reflect提供了实现Java反射的API。
#### 一、反射机制概述 Java反射机制是一种强大的工具,它允许程序在运行时检查和操作任何类、方法、构造函数和字段等元素。这种能力对于构建灵活的应用程序和框架非常有用,特别是那些需要在运行时动态地加载组件...
#### 二、Java反射机制概述 Java反射机制允许程序在运行时通过`Reflection APIs`获取类的内部信息,包括修饰符(如`public`、`static`等)、父类(如`Object`)、接口(如`Cloneable`)以及字段和方法的信息,并...
(类的加载概述和加载时机) (类加载器的概述和分类) (获取class文件对象的三种方式) (通过反射获取无参构造方法并使用) (通过反射获取带参构造方法并使用) (通过反射获取私有构造方法并使用) ...(动态代理的概述和实现)
一、Java反射机制概述 Java反射机制的核心在于Class类,它是所有类的元数据容器。通过Class对象,我们可以在运行时获取到类的完整信息,包括类名、包名、父类、接口、字段、方法等。反射机制主要涉及三个核心类:...
#### 一、JAVA反射机制概述 **反射**是在1982年由Smith首次提出的概念,指的是程序有能力访问、检测并修改其自身的状态或行为。这一概念一经提出,便迅速引起了计算机科学领域的关注,并在多个方向进行了深入的研究...
#### 一、JAVA反射机制概述 反射是Java编程语言的一个核心特性,它允许程序在运行时获取类的信息,并且可以动态地创建对象和调用方法。这种能力使得Java程序具备了高度的灵活性和扩展性。本文将深入探讨Java反射...
#### 一、Java反射机制概述 Java反射机制是Java语言中一个重要的特性,它赋予了Java程序动态操作的能力。通过反射,Java程序可以在运行时获取类的信息,并且可以创建和访问对象及其成员(如字段、方法等)。这种...
#### 一、Java反射机制概述 Java反射机制是Java语言提供的一种能在运行时分析和操作类、对象、方法等的能力。它使得开发人员可以在程序运行过程中动态地获取类的信息(例如类名、字段、方法等),并且能够动态地...