全面了解Java反射机制

什么是反射

反射 (Reflection) 是Java的特征之一,它允许运行中的Java程序获取自身的信息,并且可以操作类或对象的内部属性。

通俗的来讲就是:通过反射机制,可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。

注意这里的重点是:运行时,而不是编译时。我们常规情况下写的对象类型都是在编译期就确定下来的。而Java反射机制可以动态地创建对象并调用其属性,这样创建对象的方式便异常灵活了。

虽然通过反射可以动态的创建对象,增加了灵活性,但也不是什么地方都可用,还要考虑性能、编码量、安全、面向对象性等。

我们知道Java是面向对象的,如果通过反射机制去操作对象里面的属性或方法,一定程度上破坏了面向对象的特性。同时,通过反射机制还可以修改私有变量,也存在一定的安全性问题。

但这并不影响反射在实践中的应用,几乎各大框架多多少少都在使用Java反射机制。特别是主流的Spring框架。

功能及用途

Java反射主要提供以下功能:

在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
在运行时调用任意一个对象的方法

反射最重要的用途之一就是开发各类通用框架。以Spring为例,当基于XML进行配置Bean时,我们通常写如下代码:

<bean class="com.choupangxia.UserServiceImpl">
</bean>

Spring在启动的时候便会利用反射机制去加载对应的UserServiceImpl类,然后进行实例化。如果不存在该类则会抛出异常,通常异常中还会出现invoke方法调用的堆栈信息。

当Spring基于注解去实例化对象时,同样利用的是反射机制。下面通过一个简单demo示例,演示一下如何通过反射获得注解信息:

static void initUser(User user) throws IllegalAccessException {

// 获取User类中所有的属性(getFields无法获得private属性)
 Field[] fields = User.class.getDeclaredFields();

// 遍历所有属性
 for (Field field : fields) {
  // 如果属性上有此注解,则进行赋值操作
  if (field.isAnnotationPresent(InitSex.class)) {
   InitSex init = field.getAnnotation(InitSex.class);
   field.setAccessible(true);
   // 设置属性的性别值
   field.set(user, init.sex().toString());
   System.out.println("完成属性值的修改,修改值为:" + init.sex().toString());
  }
 }
}

更多关于Java反射的例子我们就不多说了。上面的示例现在看不懂也没关系,下面我们就来详细介绍一下Java反射机制的具体使用。

简单示例

我们通过一个简单的示例对比,来了解一下Java反射机制。首先来看正常情况下创建对象并使用对象的示例:

User user = new User();
user.setUsername("公众号:程序新视界");
user.setAge(3);

那么,当基于反射机制来达到统一效果该怎么做呢?看下面的具体实现:

@Test
public void testCreateReflect() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
  InvocationTargetException, InstantiationException {
 // 获取User所对应的Class对象
 Class clz = Class.forName("com.choupangxia.reflect.User");
 // 获取User类无参数的构造器
 Constructor constructor = clz.getConstructor();
 // 通过构造器创建User对象
 User user = (User) constructor.newInstance();
 user.setUsername("公众号:程序新视界");
 user.setAge(3);
 System.out.println("username=" + user.getUsername());
 System.out.println("age=" + user.getAge());
}

在上述过程中通过Class.forName获得User所对应的Class对象,获得构造器Constructor,通过构造器创建出来一个User对象,然后调用对应的方法。

当然,后面的步骤中也可以完全不出现User类,直接通过Class对象获得对应的Method进行调用。示例如下:

Method setUsernameMethod = clz.getMethod("setUsername", String.class);
Method setAgeMethod = clz.getMethod("setAge", int.class);

setUsernameMethod.invoke(obj,"公众号:程序新视界");
setAgeMethod.invoke(obj,3);

关于get方法也是如此操作,就不再赘述。

经过上面的实例我们已经能够正常创建对象,并使用对象了。下面就看看反射常用的API,通过这些API我们可以实现更多的更复杂的功能。

反射常用API

获取Class对象的三种方法

第一种方法:当你知道类的全路径名时,可使用Class.forName静态方法来获得Class对象。上面的示例就是通过这种方法获得:

Class clz = Class.forName("com.choupangxia.reflect.User");

第二种方法:通过“.class”获得。前提条件是在编译前就能够拿到对应的类。

Class clz = User.class;

第三种:使用类对象的getClass()方法。

User user = new User();
Class clz = user.getClass();

创建对象的两种方法

可以通过Class对象的newInstance()方法和通过Constructor 对象的newInstance()方法创建类的实例对象。

第一种:通过Class对象的newInstance()方法。

Class clz = User.class;
User user = (User) clz.newInstance();

第二种:通过Constructor对象的newInstance()方法。

Class clz = Class.forName("com.choupangxia.reflect.User");
Constructor constructor = clz.getConstructor();
User user = (User) constructor.newInstance();

其中第二种方法创建类对象可以选择特定构造方法,而通过 Class对象则只能使用默认的无参数构造方法。

Class clz = User.class;
Constructor constructor = clz.getConstructor(String.class);
User user = (User) constructor.newInstance("公众号:程序新视界");

获取类属性、方法、构造器
通过Class对象的getFields()方法获取非私有属性。

Field[] fields = clz.getFields();
for(Field field : fields){
 System.out.println(field.getName());
}

上述实例中的User对象属性都是private,无法直接通过上述方法获取,可将其中一个属性改为public,即可获取。

通过Class对象的getDeclaredFields()方法获取所有属性。

Field[] fields = clz.getDeclaredFields();
for(Field field : fields){
 System.out.println(field.getName());
}

执行打印结果:

username
age

当然针对属性的其他值也是可以获取的,针对私有属性的修改需要先调用field.setAccessible(true)方法,然后再进行赋值。关于具体应用,回头看我们最开始关于注解的实例中的使用。

获取方法的示例如下:

Method[] methods = clz.getMethods();
for(Method method : methods){
 System.out.println(method.getName());
}

打印结果:

setUsername
setAge
getUsername
getAge
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll

可以看到,不仅获取到了当前类的方法,还获取到了该类父类Object类中定义的方法。

关于获取构造器的方法上面已经讲到了,就不再赘述。而上述的这些方法在Class中都有相应的重载的方法,可根据具体情况进行灵活使用。

利用反射创建数组

最后,我们再看一个通过反射创建数组的实例。

@Test
public void createArray() throws ClassNotFoundException {
 Class<?> cls = Class.forName("java.lang.String");
 Object array = Array.newInstance(cls,5);
 // 向数组添加内容
 Array.set(array,0,"Hello");
 Array.set(array,1,"公众号");
 Array.set(array,2,"程序新视界");
 Array.set(array,3,"二师兄");
 Array.set(array,4,"Java");
 // 获取数组中指定位置的内容
 System.out.println(Array.get(array,2));
}

小结

想必经过上述的学习,对Java反射机制有了更进一步的了解,在最开始我们已经说了反射机制也是有不足的。因此,如果可能尽量使用正统的写法,但如果你在开发通用框架,则可考虑使用。

以上就是全面了解Java反射机制的详细内容,更多关于Java反射机制的资料请关注我们其它相关文章!

时间: 2020-03-25

Java反射机制的学习总结

一.什么是反射机制 简单的来说,反射机制指的是程序在运行时能够获取自身的信息.在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息. 二.哪里用到反射机制 有些时候,我们用过一些知识,但是并不知道它的专业术语是什么,在刚刚学jdbc时用过一行代码, Class.forName("com.mysql.jdbc.Driver.class").newInstance();但是那时候只知道那行代码是生成驱动对象实例,并不知道它的具体含义.听了反射机制这节课后,才知道,原来这

JAVA反射机制实例教程

本文以实例形式详细讲述了Java的反射机制,是Java程序设计中重要的技巧.分享给大家供大家参考.具体分析如下: 首先,Reflection是Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说"自审",并能直接操作程序的内部属性.例如,使用它能获得 Java 类中各成员的名称并显示出来. Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性.例如,Pascal.C 或者 C++ 中就没有办法在程序中获得函数

Java通过反射机制动态设置对象属性值的方法

/** * MethodName: getReflection<br> * Description:解析respXML 在通过反射设置对象属性值 * User: liqijing * Date:2015-7-19下午12:42:55 * @param clzzName * @param respXML * @return * @throws ClassNotFoundException * @throws DocumentException * @throws IllegalArgumentE

Java反射机制及Method.invoke详解

JAVA反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类:在运行时构造任意一个类的对象:在运行时判断任意一个类所具有的成员变量和方法:在运行时调用任意一个对象的方法:生成动态代理. 1. 得到某个对象的属性 复制代码 代码如下: public Object get

Java反射机制详解

本文较为详细的分析了Java反射机制.分享给大家供大家参考,具体如下: 一.预先需要掌握的知识(java虚拟机) java虚拟机的方法区: java虚拟机有一个运行时数据区,这个数据区又被分为方法区,堆区和栈区,我们这里需要了解的主要是方法区.方法区的主要作用是存储被装载的类 的类型信息,当java虚拟机装载某个类型的时候,需要类装载器定位相应的class文件,然后将其读入到java虚拟机中,紧接着虚拟机提取class 中的类型信息,将这些信息存储到方法区中.这些信息主要包括: 1.这个类型的全

java反射机制示例详解

1.什么是反射?一个类有多个组成部分,例如:成员变量,方法,构造方法等.反射就是加载类,并解剖出类的各个组成部分. 2.加载类java中有一个Class类用于代表某一个类的字节码.Class类既然代表某个类的字节码,那就要提供加载某个类字节码的方法:forName().   此方法用于加载某个类的字节码到内存中,并使用class对象进行封装.另外2种得到class对象的方式:类名.class对象.getClass() 先创建一个简单的Person类 复制代码 代码如下: public class

java 利用反射机制,获取实体所有属性和方法,并对属性赋值

一个普通的实体Person: private int id; private String name; private Date createdTime; ... //其它字段 // get set方法 ............... 现在需要把通过webService传过来的实体Person里面的所有字段的null值,换成"" 实现思路: 1.获取实体的所有字段,遍历 2.获取字段类型 3.调用字段的get方法,判断字段值是否为空 4.如果字段值为空,调用字段的set方法,为字段赋值

Java反射机制的实现详解

很多主流框架都使用了反射技术.像ssh框架都采用两种技术 xml做配置文件+反射技术. 与反射有关的类包. java.lang.reflect.*;和java.lang.Class; Java中所有类型(包括基本类型)都对应一个Class对象,这个Class就是java.lang.Class.即每一个类型,在Class中都有一个Class对象跟它对应.Class 没有公共构造方法.注意不是没有,是没有公共的. 如何获得Class对象 复制代码 代码如下: .针对每一个对象.getCalss(),

Java 反射机制的实例详解

Java 反射机制的实例详解 前言 今天介绍下Java的反射机制,以前我们获取一个类的实例都是使用new一个实例出来.那样太low了,今天跟我一起来学习学习一种更加高大上的方式来实现. 正文 Java反射机制定义 Java反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 用一句话总结就是反射可以实现在运行时可以知道任意一个类的属性和方法. 反射

java 代理机制的实例详解

java 代理机制的实例详解 前言: java代理分静态代理和动态代理,动态代理有jdk代理和cglib代理两种,在运行时生成新的子类class文件.本文主要练习下动态代理,代码用于备忘.对于代理的原理和机制,网上有很多写的很好的,就不班门弄斧了. jdk代理 实例代码 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; publi

java 回调机制的实例详解

java 回调机制的实例详解 序言 最近接触到了回调机制(CallBack).初识时感觉比较混乱,而且在网上搜索到的相关的讲解,要么一言带过,要么说的比较单纯的像是给CallBack做了一个定义.当然了,我在理解了回调之后,再去看网上的各种讲解,确实没什么问题.但是,对于初学的我来说,缺了一个循序渐进的过程.此处,将我对回调机制的个人理解,按照由浅到深的顺序描述一下,如有不妥之处,望不吝赐教! 开始之前,先想象一个场景:幼稚园的小朋友刚刚学习了10以内的加法. 第1章. 故事的缘起 幼师在黑板上

Java反射框架Reflections示例详解

MAVEN 坐标 <dependency> <groupId>org.reflections</groupId> <artifactId>reflections</artifactId> <version>0.9.10</version> </dependency> Reflections 的作用 Reflections通过扫描classpath,索引元数据,并且允许在运行时查询这些元数据. 获取某个类型的所有

java多态机制原理特点详解

java多态机制是什么 java中实现多态的机制是依靠父类或接口的引用指向子类.从而实现了一个对象多种形态的特性.其中父类的引用是在程序运行时动态的指向具体的实例,调用该引用的方法时,不是根据引用变量的类型中定义的方法来运行,而是根据具体的实例的方法. 概念 多态就是指一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定. 因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致

java 反射和动态代理详解及实例代码

一.java中的反射 1.通过反射加载类的属性和方法实例代码: /** * java.lang.Class 是反射的源头 * 我们创建了一个类,通过编译(javac.exe)生成对应的class文件,之后我们通过java.exe加载(jvm的类加载器加载)此class文件 * 此class文件加载到内存后,就是一个运行时类,存在缓存区,这个运行时类本事就是一个Class的实例 * 每一个运行时类只加载一次, */ Class<StudentExam> clazz = StudentExam.c

Java 反射机制实例详解

Java 反射机制实例详解 一.JAVA是动态语言吗? 一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,Java和C++一样,都不是动态语言. 但JAVA它却有着一个非常突出的动态相关机制:反射.通过反射,Java可以于运行时加载.探知和使用编译期间完全求和的类.生成其对象实体,调用其方法或者对属性设值.所以Java算是一个半动态的语言吧. 反射的概念: 在Java中的反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对

Java 反射机制详解及实例代码

Java反射详解 本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,在回过头去看看理论,会有更好的理解. 下面开始正文. [案例1]通过一个对象获得完整的包名和类名 package Reflect; /** * 通过一个对象获得完整的包名和类名 * */ class Demo{ //other codes... } class hello{ public static void main(String[] args) {