聊聊Java中的反射(一)
本文为作者原创,转载请注明出处(http://www.cnblogs.com/mar-q/)by 负赑屃
反射reflection主要为了动态操作Java代码,它的主要功能体现在Java提供的reflection library中,在《Java核心技术》中总结反射作用:1、在运行中对类的结构进行动态分析;2、在运行中查看对象;3、实现通用的数组操作;4、利用Method对象。下面分几个章节,结合书中的代码,来仔细看看这四个作用是如何实现的(第一部分是理解反射机制的关键)。
一、类的动态分析
在Java代码运行时,会为每个对象维护一个类型标识,通过Java中提供的Class类可以访问这些信息。我们知道,在Java中Object类是所有类的父类,Object类中提供了一个getClass()方法,可以返回一个Class类的实例。当你用任意一个类对象来调用这个getClass方法时,返回的Class实例对象就可以标识出类对象的属性。例如:
//根据对象获取类名
Date d = new Date();
Class dateClass = d.getClass();
String dateName = dateClass.getName();
//根据类名获取Class对象,并根据这个Class对象创建类名下的实例对象
try{
Class cl = Class.forName(dateName);
Object xx = cl.newInstance();
} cathc(ClassNotFoundException e){
e.printStackTrace();
}
Date是java.util常用的日期类,这里定义了一个Date对象d,通过d.getClass()方法获取Class类的实例,该实例包含了Date类的属性,例如类名称、类构造函数、类方法、类变量常量等等信息,通过Class类的getName()方法就可以获取类名,上面String打印出来我们可以看到结果是java.util.Date,是的,返回的类名中还包括了包名。还可以调用Class中的静态方法forName()获得类名对应的Class对象,并根据这个Class对象为类名对应的类创建实例,注意这里会抛出一个异常。
上面听起来有点绕,打个比方,这个Class类有点像盖房子的设计图,设计图中包含了房子的所有细节信息,我们可以根据房子获取到设计图,从而获得房子的尺寸、房型等等信息,也可以根据设计图再盖一栋一样的房子。
除了通过getClass和getName方法获取Class对象外,还可以通过类名.class的方法生成Class对象。例如
Class c1 = Date.class;
Class c2 = int.class;
Class c3 = Double[].class;
注意,在上面的代码中,Class对象实现代表一个类型,不一定是一个类,例如int。我们可以通过==运算实现两个Class对象的比较操作,例如date.getClass()==Date.class。
知道上面这些内容,我们基本就可以利用反射来分析类的能力了,一个类主要就是三个部分:域(Field,包括常量、变量等)、方法(Method)、构造函数(Constructor构造器),要分析一个类主要就是查看类的三部分构成。我们用reflect库中的三个类:Filed、Method、Constructor来描述类的能力,书中提供了一个打印类全部信息的方法,我会和大家一起仔细阅读这份代码:ReflectionTest.java
public class ReflectionTest{
public static void main(String[] args){
// 通过main函数参数列表或者用户输入来读取类名,保存为name
String name;
if (args.length > 0) name = args[0];
else{
Scanner in = new Scanner(System.in);
System.out.println("Enter class name (e.g. java.util.Date): ");
name = in.next();
}
try{
// 打印出类名及其父类名(包括包名)
Class cl = Class.forName(name);//通过forName()方法获取Class对象
Class supercl = cl.getSuperclass();//通过getSuperclass()获取父类Class对象
String modifiers = Modifier.toString(cl.getModifiers());//反射库中的Modifier类,可以获取类或者Field、Method、Constructor的
//public、private、static、final等修饰符描述
if (modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.print("class " + name);
if (supercl != null && supercl != Object.class) System.out.print(" extends "
+ supercl.getName());
System.out.print("\n{\n");
printConstructors(cl);//打印类的构造器
System.out.println();
printMethods(cl);//打印类中的方法
System.out.println();
printFields(cl);//打印类中的常量、变量等域信息
System.out.println("}");
}catch (ClassNotFoundException e){//如果没有找到你所输入的类,则返回一个异常
e.printStackTrace();
}
System.exit(0);
} /**
* 打印类的构造器
* @param 参数为Class对象
*/
public static void printConstructors(Class cl){
Constructor[] constructors = cl.getDeclaredConstructors();//定义了一个Constructor[]数组保存类的构造器
for (Constructor c : constructors){
String name = c.getName();//获取构造器名称
System.out.print(" ");
String modifiers = Modifier.toString(c.getModifiers());//获取构造器的修饰符
if (modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.print(name + "(");
Class[] paramTypes = c.getParameterTypes();//获取参数的列表
for (int j = 0; j < paramTypes.length; j++){
if (j > 0) System.out.print(", ");
System.out.print(paramTypes[j].getName());
}
System.out.println(");");
}
} /**
* 打印类中的所有方法,对比构造器,多了一个返回值类型
* @param 参数为Class对象
*/
public static void printMethods(Class cl){
Method[] methods = cl.getDeclaredMethods();//定义一个Method[]数组保存类中的方法
for (Method m : methods){
Class retType = m.getReturnType();//获取Method的返回值类型
String name = m.getName();//获取Method名
System.out.print(" ");
String modifiers = Modifier.toString(m.getModifiers());//获取Method的修饰符
if (modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.print(retType.getName() + " " + name + "(");
// print parameter types
Class[] paramTypes = m.getParameterTypes();//获取Method参数列表
for (int j = 0; j < paramTypes.length; j++){
if (j > 0) System.out.print(", ");
System.out.print(paramTypes[j].getName());
}
System.out.println(");");
}
} /**
* 打印类中的所有域
* @param 参数为Class对象
*/
public static void printFields(Class cl){
Field[] fields = cl.getDeclaredFields();//定义一个Field[]数组保存类的所有域
for (Field f : fields){
Class type = f.getType();//获取域的类型
String name = f.getName();
System.out.print(" ");
String modifiers = Modifier.toString(f.getModifiers());//获取域的修饰符
if (modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.println(type.getName() + " " + name + ";");
}
}
}
我们可以输入任意的类名,如java.util.Date或者你自己定义的某个类,获取该类的能力分析,注意名称不要输入错误,否则将打印一个异常信息。
/************
//二、利用反射分析对象
// 在编写代码时要想查看对象的域名和类型是一件很容易的事情,但是利用反射机制我们可以在编译时查看还不清楚的对象域。查看对象域的关键方法是Field类中的get方法,
*************/
聊聊Java中的反射(一)的更多相关文章
- Java中的反射和注解
前言 在Java中,反射机制和注解机制一直是一个很重要的概念,那么他们其中的原理是怎么样呢,我们不仅仅需要会使用,更要知其然而之所以然. 目录 反射机制 反射如何使用 注解定义 注解机制原理 注解如何 ...
- java中的反射机制在Android开发中的用处
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反 ...
- 浅说Java中的反射机制(二)
写过一篇Java中的反射机制,不算是写,应该是抄了,因为那是别人写的,这一篇也是别人写的,摘抄如下: 引自于Java基础--反射机制的知识点梳理,作者醉眼识朦胧.(()为我手记) 什么是反射? 正常编 ...
- 浅说Java中的反射机制(一)
在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...
- java中动态反射
java中动态反射能达到的效果和python的语法糖很像,能够截获方法的实现,在真实方法调用之前和之后进行修改,甚至能够用自己的实现进行特别的替代,也可以用其实现面向切片的部分功能.动态代理可以方便实 ...
- 简单聊聊java中的final关键字
简单聊聊java中的final关键字 日常代码中,final关键字也算常用的.其主要应用在三个方面: 1)修饰类(暂时见过,但是还没用过); 2)修饰方法(见过,没写过); 3)修饰数据. 那么,我们 ...
- 第89节:Java中的反射技术
第89节:Java中的反射技术 反射技术是动态的获取指定的类,和动态的调用类中的内容(没有类前就可以创建对象,将对象的动作完成,这就是动态的获取指定的类). 配置文件把具体实现的类名称定义到配置文件中 ...
- java笔记十:java中的反射
Java中,反射是一种强大的工具.它使您能够创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代表链接.反射允许我们在编写与执行时,使我们的程序代码能够接入装载到JVM中的类的内部信息,而 ...
- 【Java基础】java中的反射机制与动态代理
一.java中的反射机制 java反射的官方定义:在运行状态下,可以获取任意一个类的所有属性和方法,并且可通过某类任意一对象实例调用该类的所有方法.这种动态获取类的信息及动态调用类中方法的功能称为ja ...
随机推荐
- 可能是讲解ARM中断和中断嵌套最通俗易懂的文章
几天前一个学生问我ARM中断嵌套的问题,我才发现原来在我心中理所当然的事对学生来说理解实属不易. ARM有七种模式,我们这里只讨论SVC.IRQ和FIQ模式. 我们可以假设ARM核心有两根中断引脚 ...
- 关于Visio Studio 2012使用Nuget获取Sqlite驱动包报错:“System.Data.SQLite.EF6”的架构版本与 NuGet 的版本 2.0.30625.9003 不兼容
背景 笔者的VS2012版本比较老旧,是几年以前下载的.平时添加三方包和驱动包都是手动添加.后来了解到有Nuget这个工具,如获至宝.可是在使用过程中却出了不少问题. 最初,笔者尝试使用Nuget添加 ...
- 在0~N个数字中,取指定个数的不重复数字,要求这些数字的和为指定值,求所有结果
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Cons ...
- 利用PN532读取二代证UID
准备工作 芯片选择 NFC芯片,需要支持ISO14443 Type B协议,比如PN532 阅读ISO 14443 重点阅读如下内容: 7.3.4.1 状态转换图 7.3.5 ~ 7.3.7 REQB ...
- devstack安装openstack newton版本
准备使用devstack安装openstack N版,搞一套开发环境出来.一连整了4天,遇到各种问题,各种错误,一直到第4天下午4点多才算完成. 在这个过程中感觉到使用devstack搭建openst ...
- Codeforce E. Fire
E. Fire time limit per test 2 seconds memory limit per test 256 megabytes input standard input outpu ...
- JAVA基础---编码解码
所谓编码 即char->byte 所谓解码 即byte->char ISO-8859-1 中文字符会被黑洞吸收 全部变为"?" GB2312 汉字可以被编码为双字节 但 ...
- 黑马程序员Java基础班+就业班课程笔记全发布(持续更新)
正在黑马学习,整理了一些课程知识点和比较重要的内容分享给大家,也是给自己拓宽一些视野,仅供大家交流学习,大家有什么更好的内容可以发给我 ,现有黑马教程2000G QQ 1481135711 这是我总 ...
- 小符号反映大问题,Shell中下划线_与变量的关系。
之前写过一个根据日期和时间自动命名文件名的时候遇到一个问题. #! /bin/bash read -p "please input the filename:" filename ...
- maven编译时错误:无效的目标发行版
(转)Maven 将依赖打进一个jar包 博客分类: maven maven配置 <?xml version="1.0" encoding="UTF-8&quo ...