本文为作者原创,转载请注明出处(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. Shiro第四篇【Shiro与Spring整合、快速入门、Shiro过滤器、登陆认证】

    Spring与Shiro整合 导入jar包 shiro-web的jar. shiro-spring的jar shiro-code的jar 快速入门 shiro也通过filter进行拦截.filter拦 ...

  2. [UIKit学习]06.懒加载,模型,自定义代码段,重写构造方法

    懒加载 在get中加载,且只加载一次 - (NSArray *)shops { if (_shops == nil) { NSString *file = [[NSBundle mainBundle] ...

  3. SharedPreferences的使用

  4. Android 8.0 功能和 API

    Android 8.0 为用户和开发者引入多种新功能.本文重点介绍面向开发者的新功能. 用户体验 通知 在 Android 8.0 中,我们已重新设计通知,以便为管理通知行为和设置提供更轻松和更统一的 ...

  5. Day2 基本数据类型

    一.python数据类型 1.1数字 2 是一个整数的例子. 长整数 不过是大一些的整数. 3.23和52.3E-4是浮点数的例子.E标记表示10的幂.在这里,52.3E-4表示52.3 * 10-4 ...

  6. Message:Unable to locate element 问题解决方法

    Python断断续续学了有一段时间了,总感觉不找个小项目练练手心里没底,哪成想出门就遇到"拦路虎",一个脚本刚写完就运行报错,还好做足了心里准备,尝试自行解决. 或许网上有相关解决 ...

  7. Linux 启动详解之init

    1.init初探 init是Linux系统操作中不可缺少的程序之一.init进程,它是一个由内核启动的用户级进程,然后由它来启动后面的任务,包括多用户环境,网络等. 内核会在过去曾使用过init的几个 ...

  8. ElasticSearch入门(3) —— head插件

    #### 安装ES head插件 具体请参考github地址:https://github.com/mobz/elasticsearch-head 使用 安装Install # 在线安装head插件 ...

  9. 组合 Lucas定理

    组合 Time Limit: 1000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u [Submit]   [Go Ba ...

  10. Flip Game poj 1753

    Flip Game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 29731   Accepted: 12886 Descr ...