详解Java反射机制
反射是程序在运行状态下,动态的获取某个类的内部信息的一种操作。例如:类名,包名,所有属性的集合,所有方法的集合,构造方法的集合等。该操作发生在程序的运行时状态,所以编译器管不着有关反射的一些代码,通常只有在运行时才能暴露出程序的内部错误。反射的核心在于‘Class’这个类,本篇将从Class这个类开始介绍有关反射的一些基本的概念,主要内容如下:
- 获取Class对象
- 从Class对象中读取字段信息
- 从Class对象中读取方法信息
- 获取Class对象中的所有构造方法并使用它们动态创建类对象
- 反射的一些其他细节
一、获取Class对象
此处的Class是一个具体的类(java.lang.Class),并不是我们自定义一个类时所使用的关键字class。这是一个泛型类,通常有两种方法可以获取该对象。第一种方式,使用类名.class来获取Class对象。
Class<Integer> integerClass = int.class;
Class<Double> doubleClass = double.class;
Class<Character> characterClass = char.class;
.......
Class<Map> mapClass = Map.class;
Class<String> stringClass = String.class;
Class<Date> dateClass = Date.class;
........
无论是基本数据类型,还是一般的class类型,或是接口类型,都是可以通过.class的方式来获取与之对应的Class对象。第二中获取Class对象的方法是,通过getClass方法,当然不是所有类都提供了这个方法的,例如:Object类就提供这么一个方法:
public final native Class<?> getClass();
还有我们的数组类型:
int[] array = new int[23];
Class<?> arrayClass = array.getClass();
对于我们的基本数据类型来说,它们从根本上说并不属于任何一个类,所以它们只能通过第一种方式获取对应的Class对象。
下面看看有关我们获取到的这个Class对象的一些基本信息。首先我们可以获取有关该Class对象的名称,包,父类,父接口等信息。
//获取该Class对象代表的类名
public String getName()
//获取该Class对象代表的类名,不包含包名
public String getSimpleName()
//获取该Class对象所代表的类的包名
public Package getPackage()
//获取该类继承的父类对象
public native Class<? super T> getSuperclass();
//获取该类实现的所有接口的集合
public Class<?>[] getInterfaces()
//获取修饰在该类上的访问修饰符
public native int getModifiers();
//获取该类中所有内部类的集合
public Class<?>[] getClasses()
............
还有一些有关注解的信息,由于之前在介绍注解的时候已经说明过,此处不再赘述。上面的这些方法的使用还是比较简单,此处不再演示。
二、获取Class对象中字段信息
类中的字段包括实例域和静态域。在Java反射机制中,使用Field类管理字段信息。
//获取该类中所有字段的集合(public修饰符修饰的)
public Field[] getFields()
//返回指定名称的字段(public修饰符修饰的)
public Field getField(String name)
//获取所有字段的集合,不包括从父类继承的(包括非public)
public Field[] getDeclaredFields()
//获取指定的字段,不包含从父类继承的(可以是非public)
public Field getDeclaredField(String name)
对以上四种获取字段Field的方法做一点说明,getFields或者getField方法可以看见该类所有的被public修饰的字段,包括从父类继承的,但是不可见非public修饰的字段。getDeclaredFields或者getDeclaredField方法可以看见该类所有的字段,包括非public修饰的,但是不可见父类中的字段。接下来,我们看看对获取到的field字段可以做哪些操作:
//获取该字段的名称
public String getName()
//获取该字段的访问修饰符
public int getModifiers()
//获取指定对象中的该字段的值
public Object get(Object obj)
//设置指定对象中该字段的值
public void set(Object obj, Object value)
//获取该字段的类型
public Class<?> getType()
//判断当前程序是否具有访问该字段的权限
public boolean isAccessible()
//flag设为true表示忽略Java的访问检查机制,以允许读写非public的字段
public void setAccessible(boolean flag)
.......
对于以上的几个基本的方法,可以说见名知意,这里需要说明的是get和set方法,先看个例子:
Class<Student> studentClass = Student.class;
//这里的school是Student类中的一个属性
Field f = studentClass .getDeclaredField("school");
Student s = new Student();
f.set(s,"yanSchool");
System.out.println(f.get(s));
输出结果:yanSchool
这里的 f 代表了 school这个实例属性,如果别的类中有相同的属性,我们是可以通过 f为该属性赋值的,当然也可以从某个具有该属性的类中获取该属性的值,前提是具备目标类中的该属性的访问权限。上述的getModifiers返回的是int值,该值代表了一个修饰符,想要转换成我们能看懂的字符串的形式需要使用 Modifier.toString(int a)方法,将刚刚返回的int值作为参数传入即可。
三、获取Class对象的方法信息
无论是静态方法还是实例方法,在Java反射机制中都是使用Method这个类来管理的,一个方法对应于一个Method对象。先看怎么通过Class对象获取其中的方法。
//返回所有被public修饰的方法的集合,包括父类的
public Method[] getMethods()
//返回指定的被public修饰的方法,包括父类中的
public Method getMethod(String name, Class<?>... parameterTypes)
//返回所有的方法的集合(可以有非public),不包括父类的
public Method[] getDeclaredMethods()
//返回本类中声明的指定名称和参数类型的方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
对于以上四个方法需要说明一点的是,getMethod或者getDeclaredMethod在获取指定方法的时候,需要传入该方法的形参类型,如果没有传入或者传入错误就会抛出NoSuchMethodException异常。因为方法名和方法参数类型(个数)是唯一确定一个方法的凭据。对于获取到的Method方法有以下一些操作:
//获取该方法的方法名
public String getName()
public int getModifiers()
//获取该方法的返回类型
public Class<?> getReturnType()
//获取所有参数的类型
public Class<?>[] getParameterTypes()
//获取方法声明抛出的异常类型
public Class<?>[] getExceptionTypes()
//将该方法在指定的对象上执行,有形参的需要传入形参值
public Object invoke(Object obj, Object... args)
....//还有一些有关注解的操作,此处不再赘述
上述方法中的invoke方法和之前介绍的字段的get/set方法一样,需要指定目的对象才能使用,因为他们只是代表了具体的一个字段或者一个方法。
public class Student extends People {
public String school;
private int sno;
public void sayHello(String str){
System.out.println("hello "+str);
}
public void sayHello(int s){
System.out.println("my age is "+s);
}
}
public static void main(String[] args){
Class<Student> studentClass = Student.class;
Method method = studentClass.getMethod("sayHello",String.class);
method.invoke(new Student(),"walker");
}
输出结果:hello walker
四、获取构造方法和创建实例对象
一旦我们获取到了Class对象,我们就可以通过以下的方法进一步获取其中的构造方法,并使用它们创建一个实例对象。
//获取所有被public修饰的构造方法,不包含父类中的
public Constructor<?>[] getConstructors()
//返回指定的构造方法,可以是非public修饰的
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
//返回所有的构造方法,可以包含非public修饰的
public Constructor<?>[] getDeclaredConstructors()
//获取指定的被pubic修饰的构造方法,不包含父类中的
public Constructor<T> getConstructor(Class<?>... parameterTypes)
以上的方法和之前介绍的字段Field,方法Method很是相似。下面我们看看如何使用Constructor做一些事情。
public String getName()
public int getModifiers()
public Class<?>[] getParameterTypes()
//创建该类的实例对象
public T newInstance(Object ... initargs)
........一些注解有关的信息,可以查看之前的文章
我们主要看看如何通过 newInstance 创建一个实例对象:
public class Student extends People {
public String school;
publicint sno;
public Student(String school,int sno){
this.school=school;
this.sno = sno;
}
public void sayHello(String str){
System.out.println("hello "+str);
}
public void sayHello(int s){
System.out.println("my age is "+s);
}
}
public static void main(String[] args){
Class<Student> studentClass = Student.class;
Constructor constructor = studentClass.getConstructor(String.class,int.class);
Student s = (Student) constructor.newInstance("walker", 21);
System.out.println(s.school+" "+s.sno);
}
输出结果:walker 21
五、反射机制的一些细节
前面我们一直讨论的都是具体的类,我们可以从这些类中获取到字段,方法,构造器,注解等。java.lang.reflect包中对数组类型增添了专门的类Array来实现反射,这里的Array和数组中的Arrays是不同的。
//创建指定元素类型、指定长度的数组,
public static Object newInstance(Class<?> componentType, int length)
//创建多维数组
public static Object newInstance(Class<?> componentType, int... dimensions)
//获取数组array指定的索引位置index处的值
public static native Object get(Object array, int index)
//修改数组array指定的索引位置index处的值为value
public static native void set(Object array, int index, Object value)
//返回数组的长度
public static native int getLength(Object array)
我们可以通过Array类在运行时动态创建数组和操作数组中的元素,而不必想之前一样必须在编译之前完成数组的创建。需要注意的是此处返回的数组类型是Object而非Object[],那时因为前者可以转化成具体类型的数组,后者则不能。
至此,反射的基本内容介绍完了,我们应该知道,虽然反射很是灵活,可以动态的读取类的信息,动态的创建实例对象和数组等,但是没有了编译器的一层检查,很容易导致运行是异常。如果能够用接口来完成的,尽量使用接口来完成。
理解不到之处,还望大家不吝赐教!
详解Java反射机制的更多相关文章
- Java 基础之详解 Java 反射机制
一.什么是 Java 的反射机制? 反射(Reflection)是Java的高级特性之一,是框架实现的基础,定义:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法: ...
- 详解Java反射各种应用
Java除了给我们提供在编译期得到类的各种信息之外,还通过反射让我们可以在运行期间得到类的各种信息.通过反射获取类的信息,得到类的信息之后,就可以获取以下相关内容: Class对象 构造器 变量 方法 ...
- Java 类型信息详解和反射机制
本文部分摘自 On Java 8 RTTI RTTI(RunTime Type Information)运行时类型信息,能够在程序运行时发现和使用类型信息,把我们从只能在编译期知晓类型信息并操作的局限 ...
- java反射机制深入详解
java反射机制深入详解 转自:http://www.cnblogs.com/hxsyl/archive/2013/03/23/2977593.html 一.概念 反射就是把Java的各种成分映射成 ...
- Java反射机制详解
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反 ...
- Java 反射机制详解(下)
续:Java 反射机制详解(上) 三.怎么使用反射 想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属 ...
- Java 反射机制详解(上)
一.什么是反射 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java ...
- java反射机制详解 及 Method.invoke解释
JAVA反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方法的功能称为ja ...
- Java反射机制详解(3) -java的反射和代理实现IOC模式 模拟spring
IOC(Inverse of Control) 可翻译为“控制反转”,但大多数人都习惯将它称为“依赖注入”.在Spring中,通过IOC可以将实现类.参数信息等配置在其对应的配置文件中,那么当 需要更 ...
随机推荐
- 在python&numpy中切片(slice)
在python&numpy中切片(slice) 上文说到了,词频的统计在数据挖掘中使用的频率很高,而切片的操作同样是如此.在从文本文件或数据库中读取数据后,需要对数据进行预处理的操作.此时就 ...
- 完全关闭IIS日志,包括System32下的LogFile
早上突然发现网站访问不了了,登陆服务器一看,是C盘满了. 查一看,是IIS产生了70多G的日志,但明明已关闭日志了,还是会产生. 产生的目录在:C:\Windows\System32\LogFiles ...
- Boost库安装(实测vs2012)
1.下载boost库,我这边下载的是目前最新的:boost_1_63_0.7z 2.解压到本地目录:我这边是:D:\Program Files 3.cmd窗口,以管理员权限打开,执行D:\Progra ...
- celldb.cc
欢迎光临 celldb.cc 的新博客 老博客的内容就不搬迁了, 工作量太大. http://celldb.cc 主要功能: 1 话单基站轨迹分析 2 基站查询 3 邻近基站查询 4 CDMA根据城市 ...
- 初识vuex
1.简介 vuex是 vue官方推荐的一个状态管理器.当我们遇到很多状态改变时,组件之间的通信就会变得复杂,这时候vuex的强大就展现出来. 我们从vuex的原理以及vuex的api两个部分介绍vue ...
- Redis数据迁移方案
场景 Redis实例A ---> Redis实例B,整库全量迁移 方案一: mac环境 brew install npm npm install redis-dump -g 针对RedisA: ...
- cookie设置今日不提醒功能
需求:为了实现 退出页面时 [启动今日不提醒]的功能.采用纯js.cookie来实现. /****今日不提醒 start *****/ var userid = <%=UserId %>; ...
- 2017年要学习的JavaScript的顶级框架和主题
JavaScript的流行促进了一个非常活跃的由相关技术,框架和库组成的生态圈的发展.整个生态圈的多样性和活跃性越来越强,这让许多人变得越来越困惑. 你应该了解些什么技术呢? 我们应该将时间花费在 ...
- sass ruby环境 安装配置,使用sublime text3 中sass
首先,你想要使用sass的话,就必须依赖于ruby环境.所以,你要下一个ruby.具体的链接应该是(http://rubyinstaller.org/downloads).下载相应的版本.- 下载好之 ...
- 2017-3-28 javaScript DOM 操作
一.DOM的基本概念:DOM是文档对象模型,这种模型为树模型:文档是指标签文档:对象是指文档中每个元素:模型是指抽象化得东西. 二.Windows 对象操作:1.属性和方法:属性(值或者子对象):o ...