什么是反射,为什么它是有用的,以及如何使用它?

1.什么是反射?

“反射通常是JVM中运行的程序需要检测和修改运行时程序的行为的一种能力。”这个概念通常与内省(Introspection)混淆。以下是这两个术语在维基百科中的定义:

  1. 内省是指计算机程序在运行时检查对象类型的一种能力,通常也可以称作运行时类型检查。
  2. 反射是指计算机程序在运行时可以访问、检测和修改它本身状态或行为的一种能力。

从他们的定义可以看出,内省是反射的一个子集。有些语言支持内省,但不支持反射,如C++。

内省例子:instanceof运算符用于确定一个对象是否属于一个特定的类。

if(obj instanceof Dog){
   Dog d = (Dog)obj;
   d.bark();
}

反射例子:Class.forName()方法通过类或接口的名称(一个字符串和完全限定名)来返回对应Class的对象。forName方法会对类初始化。

// with reflection
Class<?> c = Class.forName("classpath.and.classname");
Object dog = c.newInstance();
Method m = c.getDeclaredMethod("bark", new Class<?>[0]);
m.invoke(dog);

在Java中,更关注于反射而非内省,因为你不能改变一个对象的结构。

2.为什么我们需要反射?

反射能够让我们:

  • 运行时检测一个对象所属的类;
  • 运行时构造一个类的对象;
  • 运行时检测一个类的字段和方法;
  • 运行时调用一个对象的任意方法;
  • 修改构造函数、方法、字段的访问权限,AccessibleObject的setAccessible(boolean flag)方法;
  • 等等

反射是框架中常用的方法。

例如,JUnit通过反射来查找标记为 @Test 注解的方法,并在运行单元测试时调用这些方法。

对于Web框架,产品开发人员在配置文件中定义接口和类的实现。通过使用反射,框架可以快速动态地初始化所需要的类。

例如,Spring框架使用bean的配置,如:

<bean id="someID" class="com.programcreek.Foo">
   <property name="someField" value="someValue" />
</bean>

当Spring上下文处理<bean>元素时,将使用Class.forName(String)与参数"com.programcreek.Foo"来实例化类。然后,它会再次使用反射来得到<property>元素对应的setter方法并设置指定的值。

相同的机制也用于Servlet web applications:

<servlet>
   <servlet-name>someServlet</servlet-name>
   <servlet-class>com.programcreek.WhyReflectionServlet</servlet-class>
<servlet>

3.如何使用反射?

通过以下几个典型的小例子来学习如何使用反射。

例1:获取对象的类名称。

package myreflection;
import java.lang.reflect.Method;

public class ReflectionHelloWorld {
   public static void main(String[] args){
        Foo f = new Foo();
        System.out.println(f.getClass().getName());           
   }
}

class Foo {
   public void print() {
        System.out.println("abc");
   }
}

输出:

myreflection.Foo

例2:调用未知对象的方法。

对于下面的代码示例,假象一下对象的类型是未知的。通过使用反射,代码可以使用该对象,并找出对象有一个名为“print”的方法,然后调用它。

package myreflection;
import java.lang.reflect.Method;

public class ReflectionHelloWorld {
   public static void main(String[] args){
        Foo f = new Foo();

Method method;
       try {
            method = f.getClass().getMethod("print", new Class<?>[0]);
            method.invoke(f);
       } catch (Exception e) {
            e.printStackTrace();
       }
   }
}

class Foo {
   public void print() {
        System.out.println("abc");
   }
}

abc

例3:从Class实例创建对象

 
package myreflection;

public class ReflectionHelloWorld {
   public static void main(String[] args){
       //create instance of "Class"
       Class<?> c = null;
       try{
            c=Class.forName("myreflection.Foo");
       }catch(Exception e){
            e.printStackTrace();
       }

//create instance of "Foo"
       Foo f = null;

try {
            f = (Foo) c.newInstance();
       } catch (Exception e) {
            e.printStackTrace();
       }

f.print();
   }
}

class Foo {
   public void print() {
        System.out.println("abc");
   }
}

示例4:获取构造函数和创建实例。

package myreflection;

import java.lang.reflect.Constructor;

public class ReflectionHelloWorld {
   public static void main(String[] args){
       //create instance of "Class"
       Class<?> c = null;
       try{
            c=Class.forName("myreflection.Foo");
       }catch(Exception e){
            e.printStackTrace();
       }

//create instance of "Foo"
       Foo f1 = null;
        Foo f2 = null;

//get all constructors
       Constructor<?> cons[] = c.getConstructors();

try {
            f1 = (Foo) cons[0].newInstance();
            f2 = (Foo) cons[1].newInstance("abc");
       } catch (Exception e) {
            e.printStackTrace();
       }

f1.print();
        f2.print();
   }
}

class Foo {
    String s;

public Foo(){}

public Foo(String s){
       this.s=s;
   }

public void print() {
        System.out.println(s);
   }
}

null
abc

此外,你可以使用Class实例来获取该类实现的接口,父类,声明的字段等。

例5:通过反射来修改数组的大小。

package myreflection;

import java.lang.reflect.Array;

public class ReflectionHelloWorld {
   public static void main(String[] args) {
       int[] intArray = { 1, 2, 3, 4, 5 };
       int[] newIntArray = (int[]) changeArraySize(intArray, 10);
        print(newIntArray);

String[] atr = { "a", "b", "c", "d", "e" };
        String[] str1 = (String[]) changeArraySize(atr, 10);
        print(str1);
   }

// change array size
   public static Object changeArraySize(Object obj, int len) {
        Class<?> arr = obj.getClass().getComponentType();
        Object newArray = Array.newInstance(arr, len);

//do array copy
       int co = Array.getLength(obj);
        System.arraycopy(obj, 0, newArray, 0, co);
       return newArray;
   }

// print
   public static void print(Object obj) {
        Class<?> c = obj.getClass();
       if (!c.isArray()) {
           return;
       }

System.out.println("\nArray length: " + Array.getLength(obj));

for (int i = 0; i < Array.getLength(obj); i++) {
            System.out.print(Array.get(obj, i) + " ");
       }
   }
}

输出:

Array length: 10
1 2 3 4 5 0 0 0 0 0
Array length: 10
a b c d e null null null null null

总结

上面的代码示例仅仅展现了Java反射提供的非常小的一部分功能。阅读这些例子只能让你初识Java反射,你需要在Oracle的官网阅读相关文档来了解更多信息。

java反射教程的更多相关文章

  1. 超详细的java反射教程

    看技术博客时,看到关于java反射的博文,写的非常好.猛击下面的地址,开始java反射之旅 中文翻译地址:http://ifeve.com/java-reflection/ 英文原版地址:http:/ ...

  2. 转:Java反射教程

    原文来自于:http://www.importnew.com/9078.html 什么是反射?反射有什么用处? 1. 什么是反射? “反射(Reflection)能够让运行于JVM中的程序检测和修改运 ...

  3. 非常easy的JAVA反射教程

    原创文章,转载请注明. 反射能够动态载入类,实例化对象,调用方法.如今以下面样例解说. 一.载入类. Class clazz = Class.forName("java.lang.Strin ...

  4. Java反射——引言

    Java反射——引言 原文地址:http://tutorials.jenkov.com/java-reflection/index.html *By Jakob Jenkov Java的反射机制使得它 ...

  5. 【译】1. Java反射——引言

    原文地址:http://tutorials.jenkov.com/java-reflection/index.html *By Jakob Jenkov Java的反射机制使得它可以在运行时检查类.接 ...

  6. java反射基础知识(三)

    原文地址:http://tutorials.jenkov.com/java-reflection/index.html http://www.cnblogs.com/penghongwei/p/329 ...

  7. Java注解教程:自定义注解示例,利用反射进行解析

    Java注解能够提供代码的相关信息,同时对于所注解的代码结构又没有直接影响.在这篇教程中,我们将学习Java注解,如何编写自定义注解,注解的使用,以及如何使用反射解析注解. 注解是Java 1.5引入 ...

  8. Java基础教程:反射基础

    Java基础教程:反射基础 引入反射 反射是什么 能够动态分析类能力的程序称为反射. 反射是一种很强大且复杂的机制. Class类 在程序运行期间,Java运行时系统始终为所有对象维护一个被称为运行时 ...

  9. 8千字干货教程|java反射精讲

    java反射机制精讲 目录 1. 反射机制的概念 2. 反射的基础Class类 3. 反射的用法 4. 反射的应用示例 作者简介:全栈学习笔记,一个正在努力的人 微信公众号:公众号日更,精彩美文每天推 ...

随机推荐

  1. Oracle管理监控之监控表空间使用率脚本

    SELECT D.TABLESPACE_NAME,       SPACE "SUM_SPACE(M)",       BLOCKS SUM_BLOCKS,       SPACE ...

  2. SmartSprites 智能批量合并 CSS 雪碧图

    做前端的稍微有点经验的都知道 可以通过合并小图片 来减少请求数, 最早可能都是通过 fw.ps 等工具来手动合并, 这种方式的缺点就不吐槽了,效率低,可维护性差 等等 .... 一些很厉害的人,往往会 ...

  3. Linux squid 缓存服务器

    一.简介 代理服务器英文全称是Proxy Server,其功能就是代理网络用户去取得网络信息. Squid是一个缓存Internet 数据的软件,其接收用户的下载申请,并自动处理所下载的数据.当一个用 ...

  4. stark - 分页、search、actions

    一.分页 效果图 知识点 1.分页 {{ showlist.pagination.page_html|safe }} 2.page.py class Pagination(object): def _ ...

  5. Doing Homework---hdu1074(状态压缩&&记忆化搜索)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1074 有n(n<=15)门课需要做作业,每门课所需时间是used_time以及每门课作业上交的最 ...

  6. 无题II---hdu2236(二分,匈牙利)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2236 要求最大值与最小值的差值最小,是通过枚举边的下限和上限来完成 只需要用二分找一个区间,然后不断枚 ...

  7. Python开发【笔记】:探索Python F-strings

    F-strings 在python3.6.2版本中,PEP 498 提出一种新型字符串格式化机制,被称为“字符串插值”或者更常见的一种称呼是F-strings(主要因为这种字符串的第一个字母是f) 简 ...

  8. spring boot由浅入深(一)jdk安装

    1jdk说明 jdk是java提供了运行环境,简单的说就是给java语言制定了规则,并且提供了工具 jdk官网网站:http://www.oracle.com/technetwork/java/jav ...

  9. 第1章 1.6计算机网络概述--OSI参考模型

    ISO七层模式:国际标准组织对互联网通信规则进行的定义. 7.应用层:所有能产生网络流量的程序,如:QQ. 6.表示层:传输前对数据进行进行处理,是一种数据处理的规则,如:加密.压缩.传输二进制(图片 ...

  10. arc 和 非arc兼容

    1,选择项目中的Targets,选中你所要操作的Target, 2,选Build Phases,在其中Complie Sources中选择需要ARC的文件双击, 并在输入框中输入:-fobjc-arc ...