zoukankan      html  css  js  c++  java
  • java的反射机制

    本文转载自:http://www.importnew.com/9078.html

    1. 什么是反射?

    “反射(Reflection)能够让运行于JVM中的程序检测和修改运行时的行为。”这个概念常常会和内省(Introspection)混淆,以下是这两个术语在Wikipedia中的解释:

    1. 内省用于在运行时检测某个对象的类型和其包含的属性
    2. 反射用于在运行时检测和修改某个对象的结构及其行为

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

    内省示例:instanceof 运算符用于检测某个对象是否属于特定的类。

    1 if (obj instanceof Dog) {
    2     Dog d = (Dog) obj;
    3     d.bark();
    4 }

    反射示例:Class.forName()方法可以通过类或接口的名称(一个字符串或完全限定名)来获取对应的Class对象。forName方法会触发类的初始化。

    1 // 使用反射
    2 Class<?> c = Class.forName("classpath.and.classname");
    3 Object dog = c.newInstance();
    4 Method m = c.getDeclaredMethod("bark", new Class<?>[0]);
    5 m.invoke(dog);

    在Java中,反射更接近于内省,因为你无法改变一个对象的结构。虽然一些API可以用来修改方法和属性的可见性,但并不能修改结构。

    2. 我们为何需要反射?

    反射能够让我们:

    • 在运行时检测对象的类型;
    • 动态构造某个类的对象;
    • 检测类的属性和方法;
    • 任意调用对象的方法;
    • 修改构造函数、方法、属性的可见性;
    • 以及其他。

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

    例如,JUnit通过反射来遍历包含 @Test 注解的方法,并在运行单元测试时调用它们。(这个连接中包含了一些JUnit的使用案例)

    对于Web框架,开发人员在配置文件中定义他们对各种接口和类的实现。通过反射机制,框架能够快速地动态初始化所需要的类

    例如,Spring框架使用如下的配置文件:

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

    当Spring容器处理<bean>元素时,会使用Class.forName("com.programcreek.Foo")来初始化这个类,并再次使用反射获取<property>元素对应的setter方法,为对象的属性赋值。

    Servlet也会使用相同的机制:

     
    1 <servlet>
    2     <servlet-name>someServlet</servlet-name>
    3     <servlet-class>com.programcreek.WhyReflectionServlet</servlet-class>
    4 <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");
        }
    }

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

    在下列代码中,设想对象的类型是未知的。通过反射,我们可以判断它是否包含print方法,并调用它。

     
     1 package myreflection;
     2 import java.lang.reflect.Method;
     3  
     4 public class ReflectionHelloWorld {
     5     public static void main(String[] args){
     6         Foo f = new Foo();
     7  
     8         Method method;
     9         try {
    10             method = f.getClass().getMethod("print", new Class<?>[0]);
    11             method.invoke(f);
    12         } catch (Exception e) {
    13             e.printStackTrace();
    14         }           
    15     }
    16 }
    17  
    18 class Foo {
    19     public void print() {
    20         System.out.println("abc");
    21     }
    22 }
     

    示例3:创建对象

     1 package myreflection;
     2  
     3 public class ReflectionHelloWorld {
     4     public static void main(String[] args){
     5         // 创建Class实例
     6         Class<?> c = null;
     7         try{
     8             c=Class.forName("myreflection.Foo");
     9         }catch(Exception e){
    10             e.printStackTrace();
    11         }
    12  
    13         // 创建Foo实例
    14         Foo f = null;
    15  
    16         try {
    17             f = (Foo) c.newInstance();
    18         } catch (Exception e) {
    19             e.printStackTrace();
    20         }   
    21  
    22         f.print();
    23     }
    24 }
    25  
    26 class Foo {
    27     public void print() {
    28         System.out.println("abc");
    29     }
    30 }
     

     示例4:获取构造函数,并创建对象。

     
     1 package myreflection;
     2  
     3 import java.lang.reflect.Constructor;
     4  
     5 public class ReflectionHelloWorld {
     6     public static void main(String[] args){
     7         // 创建Class实例
     8         Class<?> c = null;
     9         try{
    10             c=Class.forName("myreflection.Foo");
    11         }catch(Exception e){
    12             e.printStackTrace();
    13         }
    14  
    15         // 创建Foo实例
    16         Foo f1 = null;
    17         Foo f2 = null;
    18  
    19         // 获取所有的构造函数
    20         Constructor<?> cons[] = c.getConstructors();
    21  
    22         try {
    23             f1 = (Foo) cons[0].newInstance();
    24             f2 = (Foo) cons[1].newInstance("abc");
    25         } catch (Exception e) {
    26             e.printStackTrace();
    27         }   
    28  
    29         f1.print();
    30         f2.print();
    31     }
    32 }
    33  
    34 class Foo {
    35     String s; 
    36  
    37     public Foo(){}
    38  
    39     public Foo(String s){
    40         this.s=s;
    41     }
    42  
    43     public void print() {
    44         System.out.println(s);
    45     }
    46 }

    此外,你可以通过Class实例来获取该类实现的接口、父类、声明的属性等。

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

     
     1 package myreflection;
     2  
     3 import java.lang.reflect.Array;
     4  
     5 public class ReflectionHelloWorld {
     6     public static void main(String[] args) {
     7         int[] intArray = { 1, 2, 3, 4, 5 };
     8         int[] newIntArray = (int[]) changeArraySize(intArray, 10);
     9         print(newIntArray);
    10  
    11         String[] atr = { "a", "b", "c", "d", "e" };
    12         String[] str1 = (String[]) changeArraySize(atr, 10);
    13         print(str1);
    14     }
    15  
    16     // 修改数组的大小
    17     public static Object changeArraySize(Object obj, int len) {
    18         Class<?> arr = obj.getClass().getComponentType();
    19         Object newArray = Array.newInstance(arr, len);
    20  
    21         // 复制数组
    22         int co = Array.getLength(obj);
    23         System.arraycopy(obj, 0, newArray, 0, co);
    24         return newArray;
    25     }
    26  
    27     // 打印
    28     public static void print(Object obj) {
    29         Class<?> c = obj.getClass();
    30         if (!c.isArray()) {
    31             return;
    32         }
    33  
    34         System.out.println("
    Array length: " + Array.getLength(obj));
    35  
    36         for (int i = 0; i < Array.getLength(obj); i++) {
    37             System.out.print(Array.get(obj, i) + " ");
    38         }
    39     }
    40 }

    原文链接: Programcreek 翻译: ImportNew.com 薄荷脑
    译文链接: http://www.importnew.com/9078.html

  • 相关阅读:
    Code Forces Gym 100886J Sockets(二分)
    CSU 1092 Barricade
    CodeChef Mahesh and his lost array
    CodeChef Gcd Queries
    CodeChef GCD2
    CodeChef Sereja and LCM(矩阵快速幂)
    CodeChef Sereja and GCD
    CodeChef Little Elephant and Balance
    CodeChef Count Substrings
    hdu 4001 To Miss Our Children Time( sort + DP )
  • 原文地址:https://www.cnblogs.com/lintong/p/4369701.html
Copyright © 2011-2022 走看看