本文为作者原创,转载请注明出处(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中的反射(一)的更多相关文章

  1. Java中的反射和注解

    前言 在Java中,反射机制和注解机制一直是一个很重要的概念,那么他们其中的原理是怎么样呢,我们不仅仅需要会使用,更要知其然而之所以然. 目录 反射机制 反射如何使用 注解定义 注解机制原理 注解如何 ...

  2. java中的反射机制在Android开发中的用处

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反 ...

  3. 浅说Java中的反射机制(二)

    写过一篇Java中的反射机制,不算是写,应该是抄了,因为那是别人写的,这一篇也是别人写的,摘抄如下: 引自于Java基础--反射机制的知识点梳理,作者醉眼识朦胧.(()为我手记) 什么是反射? 正常编 ...

  4. 浅说Java中的反射机制(一)

    在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...

  5. java中动态反射

    java中动态反射能达到的效果和python的语法糖很像,能够截获方法的实现,在真实方法调用之前和之后进行修改,甚至能够用自己的实现进行特别的替代,也可以用其实现面向切片的部分功能.动态代理可以方便实 ...

  6. 简单聊聊java中的final关键字

    简单聊聊java中的final关键字 日常代码中,final关键字也算常用的.其主要应用在三个方面: 1)修饰类(暂时见过,但是还没用过); 2)修饰方法(见过,没写过); 3)修饰数据. 那么,我们 ...

  7. 第89节:Java中的反射技术

    第89节:Java中的反射技术 反射技术是动态的获取指定的类,和动态的调用类中的内容(没有类前就可以创建对象,将对象的动作完成,这就是动态的获取指定的类). 配置文件把具体实现的类名称定义到配置文件中 ...

  8. java笔记十:java中的反射

    Java中,反射是一种强大的工具.它使您能够创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代表链接.反射允许我们在编写与执行时,使我们的程序代码能够接入装载到JVM中的类的内部信息,而 ...

  9. 【Java基础】java中的反射机制与动态代理

    一.java中的反射机制 java反射的官方定义:在运行状态下,可以获取任意一个类的所有属性和方法,并且可通过某类任意一对象实例调用该类的所有方法.这种动态获取类的信息及动态调用类中方法的功能称为ja ...

随机推荐

  1. Linux服务器硬盘状态查看

    首先执行fdisk -l最底下 Device Start End Sectors Size Type /dev/vda1 2048 6143 4096 2M BIOS boot /dev/vda2 6 ...

  2. layer子层给父层页面元素赋值,以达到向父层页面传值的效果

    父层: jsp中: //页面上添加一个隐藏的输入框待用于被子层设置value,从而将子层的数据传递到此页面 <input type="hidden" id="get ...

  3. 【个人笔记】《知了堂》MySQL中的数据类型

    MySQL中的数据类型 1.整型 MySQL数据类型 含义(有符号) tinyint(m) 1个字节  范围(-128~127) smallint(m) 2个字节  范围(-32768~32767) ...

  4. JS--微信浏览器复制到剪贴板实现

    由于太忙很久没写博客了,如有错误遗漏,请指出,感谢! 首先这里要注意,是微信浏览器下的解决方案,其他浏览器请自行测试. 先说复制到剪贴板主要有什么使用场景: 优惠券优惠码,需要用户复制 淘宝商品,需要 ...

  5. AngularJS的$rootScope和$scope联系和区别

    scope是html和单个controller之间的桥梁,数据绑定就靠他了. rootscope是各个controller中scope的桥梁.用rootscope定义的值,可以在各个controlle ...

  6. 深入理解计算机系统chapter7

    链接:将各种代码和数据部分收集起来并组合成为单一文件的过程,这个文件可被加载到存储器并执行. 在运行时,和一个在存储器中的程序链接起来 二.静态链接库与动态链接库 静态连接库就是把(lib)文件中用到 ...

  7. Java钉钉开发_01_开发前的准备

    源码已上传GitHub:传送门 一.准备事项 1.1  一个能在公网上访问的项目: 参见:Java微信开发_02_本地服务器映射外网 1.2  一个钉钉账号 去注册 1.3 创建一个应用 登录钉钉后台 ...

  8. 【重点突破】——Canvas技术绘制随机改变的验证码

    一.引言 本文主要是我在学习Canvas技术绘图时的一个小练习,绘制随机改变的验证码图片,虽然真正的项目里不这么做,但这个练习是一个掌握Canvas技术很好的综合练习.(真正的项目中验证码图片使用服务 ...

  9. MySQL之最基本命令

    前言:以下是数据库最基础最常用的命令,特别适用初学者练习,希望通过不断练习这些命令来熟练操作.巩固基础,因为只有不断地练习才能将知识真正变成自己的东西. 快速查看以下内容: 操作 命令 创建数据库 C ...

  10. H264 NAL解析

    NAL全称Network Abstract Layer,即网络抽象层.在H.264/AVC视频编码标准中,整个系统框架被分为了两个层面:视频编码层面(VCL)和网络抽象层面(NAL).其中,前者负责有 ...