java之反射技术(一)

来源:互联网 发布:javascript常用函数 编辑:程序博客网 时间:2024/06/05 15:23

什么叫JAVA反射技术(Reflection)?

谈到反射,我们首先了解下动态语言。

“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。

从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。


尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。

这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。

换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),

并生成其对象实体、或对其fields设值、或唤起其methods

这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。

Reflection和introspection是常被并提的两个术语。


那在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?

答案是肯定的。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。


JAVA反射提供了那些功能

  • 在运行时判断任意一个对象所属的类。

  • 在运行时构造任意一个类的对象。

  • 在运行时判断任意一个类所具有的成员变量和方法。

  • 在运行时调用任意一个对象的方法。
Reflection 是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)、实现之interfaces(例如Serializable),也包括fields和methods的所有信息,并可于运行时改变fields内容或调用methods。


JAVA反射会用到哪些类

在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中:
  • Class类:代表一个类。

  • Field 类:代表类的成员变量(成员变量也称为类的属性)。

  • Method类:代表类的方法。

  • Constructor 类:代表类的构造方法。

  • Array类:提供了动态创建数组,以及访问数组的元素的静态方法

JAVA反射我们怎么用

Class是Reflection起源,针对任何你想探勘的class,唯有先为它产生一个Class Object,接下来才能经由后者唤醒
为数十多个的Reflection APIs

1、如何获得获得一个类以及类的相关信息
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 通过一个对象获得完整的包名和类名  
  3.  * @param args 
  4.  */  
  5. public static void main(String[] args) {  
  6.     Demo demo=new Demo();  
  7.       
  8.     System.out.println(demo.getClass().getName());  
  9.       
  10.     System.out.println(Demo.class.getName());  
  11.       
  12.     System.out.println(Demo.class.getSimpleName());  
  13. }  
打印结果:
com.reflect.Demo
com.reflect.Demo
Demo


这个例子告诉我们既可以通过对象调用getClass方法获取类的信息,也可以直接类.class的形式。


2、我们所常见的Class.forName(" ");
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public static void main(String[] args) {  
  2.     Class<?> demo1=null;  
  3.     Class<?> demo2=null;  
  4.     Class<?> demo3=null;  
  5.     try   
  6.     {  
  7.         demo1=Class.forName("com.reflect.Demo");  
  8.     }   
  9.     catch (ClassNotFoundException e)   
  10.     {  
  11.         e.printStackTrace();  
  12.     }  
  13.     demo2=new Demo().getClass();  
  14.     demo3=Demo.class;  
  15.     System.out.println("类名称"+demo1.getName());  
  16.     System.out.println("类名称"+demo2.getName());  
  17.     System.out.println("类名称"+demo3.getName());  
  18. }  
打印结果:
类名称com.reflect.Demo
类名称com.reflect.Demo
类名称com.reflect.Demo


记住这是第三种获得类的方式,给定完整的字符串名的类或接口,返回一个类对象。

3、通过一个类去实例化它的对象,不采取new的方式
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public static void main(String[] args) {  
  2.     Class<?> demo = null;  
  3.     try   
  4.     {  
  5.         demo = Class.forName("com.reflect.Person");  
  6.     }   
  7.     catch (ClassNotFoundException e)   
  8.     {  
  9.         e.printStackTrace();  
  10.     }         
  11.       
  12.     Person person = null;  
  13.     try   
  14.     {  
  15.         person = (Person)demo.newInstance();  
  16.     }   
  17.     catch (Exception e)   
  18.     {  
  19.         e.printStackTrace();  
  20.     }   
  21.     person.setName("jay");  
  22.     person.setAge(11);  
  23.     System.out.println(person);  
  24. }  
打印结果:
[jay||11]

这里我们应该看到了newInstance方法,调用它就能返回一个类的实例对象,注意的是,定义的类必须提供一个无参的构造方法才能通过此方法去实例化。
如果没有提供呢,我们是不是就没法通过反射的方式实例化了呢,当然不会,请看下一个示例。

4、实例化一个无参构造方法的类
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public static void main(String[] args) {  
  2.     Class<?> demo = null;  
  3.     try   
  4.     {  
  5.         demo = Class.forName("com.reflect.Person");  
  6.     }   
  7.     catch (ClassNotFoundException e)  
  8.     {  
  9.         e.printStackTrace();  
  10.     }         
  11.       
  12.        try  
  13.        {  
  14.         Person person = (Person)demo.getConstructor(new Class[]{String.class}).newInstance(new Object[]{"Rollen"});  
  15.         System.out.println(person);  
  16.        }  
  17.        catch(Exception e)  
  18.        {  
  19.         e.printStackTrace();        
  20.        }  
  21. }  
打印结果:
[Rollen||0]

因为构造方法的参数个数及类型都是未知的,所以这里用到的是传数组的方式。

5、得到一个类的所有接口
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public static void main(String[] args) {  
  2.     Class<?> demo=null;  
  3.     try  
  4.     {  
  5.         demo=Class.forName("com.reflect.People");   
  6.     }  
  7.     catch (Exception e)   
  8.     {  
  9.         e.printStackTrace();  
  10.     }   
  11.     //保存所有的接口          
  12.     Class<?> intes[]=demo.getInterfaces();   
  13.       
  14.     for (int i = 0; i < intes.length; i++)   
  15.     {  
  16.         System.out.println("实现的接口   "+intes[i].getName());    
  17.     }  
  18. }  
打印结果:
实现的接口   com.reflect.China

6、得到一个类的父类
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public static void main(String[] args) {  
  2.        Class<?> demo=null;           
  3.        try  
  4.        {               
  5.         demo=Class.forName("com.reflect.People");           
  6.        }  
  7.        catch (Exception e)   
  8.        {               
  9.         e.printStackTrace();           
  10.        }           
  11.        //取得父类           
  12.        Class<?> temp=demo.getSuperclass();           
  13.        System.out.println("继承的父类为:   "+temp.getName());   
  14. }  
打印结果:
继承的父类为:   java.lang.Object

7、得到一个类的所有构造方法
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public static void main(String[] args) {  
  2.        Class<?> demo = null;   
  3.        try  
  4.        {  
  5.         demo = Class.forName("com.reflect.People");           
  6.        }  
  7.        catch (Exception e)   
  8.        {  
  9.         e.printStackTrace();      
  10.        }  
  11.        Constructor<?>cons[]=demo.getConstructors();           
  12.        for (int i = 0; i < cons.length; i++)   
  13.        {  
  14.         System.out.println("构造方法:  "+cons[i]);     
  15.        }   
  16. }  
打印结果:
构造方法:  public com.reflect.People(java.lang.String)
构造方法:  public com.reflect.People()


8、得到所有构造方法的修饰类型及参数类型
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public static void main(String[] args){  
  2.     Class<?> demo = null;  
  3.     try   
  4.     {  
  5.         demo = Class.forName("com.reflect.People");  
  6.     }   
  7.     catch (Exception e)   
  8.     {  
  9.         e.printStackTrace();  
  10.     }  
  11.     Constructor<?> cons[] = demo.getConstructors();  
  12.     for (int i = 0; i < cons.length; i++)   
  13.     {  
  14.         Class<?> p[] = cons[i].getParameterTypes();  
  15.         System.out.print("构造方法:  ");  
  16.         // 权限修饰符  
  17.         int mo = cons[i].getModifiers();  
  18.         System.out.print(Modifier.toString(mo) + " ");  
  19.         //构造方法名字  
  20.         String consName=cons[i].getName();  
  21.         System.out.print(consName+"(");  
  22.         for (int j = 0; j < p.length; ++j)   
  23.         {  
  24.             //参数类型名字  
  25.             String typeName=p[j].getName();  
  26.             System.out.print(typeName + " arg" + i);  
  27.             if (j < p.length - 1)   
  28.             {  
  29.                 System.out.print(",");  
  30.             }  
  31.         }  
  32.         System.out.println("){}");  
  33.     }  
  34. }  
打印结果:
构造方法:  public com.reflect.People(java.lang.String arg0){}
构造方法:  public com.reflect.People(){}


9、得到属性的修饰符,及类型和名字
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public static void main(String[] args) {  
  2.     Class<?> demo = null;  
  3.     try   
  4.     {  
  5.         demo = Class.forName("com.reflect.People");  
  6.     }   
  7.     catch (Exception e)   
  8.     {  
  9.         e.printStackTrace();  
  10.     }  
  11.     System.out.println("===============本类属性========================");  
  12.     // 取得本类的全部属性  
  13.     Field[] field = demo.getDeclaredFields();  
  14.     for (int i = 0; i < field.length; i++)   
  15.     {  
  16.         // 权限修饰符  
  17.         int mo = field[i].getModifiers();  
  18.         String priv = Modifier.toString(mo);  
  19.         // 属性类型  
  20.         Class<?> type = field[i].getType();  
  21.         //属性字段名字  
  22.         String name=field[i].getName();  
  23.         System.out.println(priv + " " + type.getName() + " "+ name + ";");  
  24.     }  
  25.     System.out.println("===============实现的接口或者父类的属性========================");  
  26.     // 取得实现的接口或者父类的属性  
  27.     Field[] filed1 = demo.getFields();  
  28.     for (int j = 0; j < filed1.length; j++)   
  29.     {  
  30.         // 权限修饰符  
  31.         int mo = filed1[j].getModifiers();  
  32.         String priv = Modifier.toString(mo);  
  33.         // 属性类型  
  34.         Class<?> type = filed1[j].getType();  
  35.         //属性字段名字  
  36.         String name=filed1[j].getName();  
  37.         System.out.println(priv + " " + type.getName() + " "+ name + ";");  
  38.     }  
  39. }  
打印结果:
===============本类属性========================
private java.lang.String sex;
===============实现的接口或者父类的属性========================
public static final java.lang.String name;
public static final int age;


10、通过反射的方式调用某个对象的方法
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public static void main(String[] args) {  
  2.     Class<?> demo = null;  
  3.     try   
  4.     {  
  5.         demo = Class.forName("com.reflect.People");  
  6.     }   
  7.     catch (Exception e)   
  8.     {  
  9.         e.printStackTrace();  
  10.     }  
  11.     try   
  12.     {  
  13.         // 调用Person类中的sayChina方法  
  14.         Method method = demo.getMethod("sayChina");  
  15.         method.invoke(demo.newInstance());  
  16.         // 调用Person的sayHello方法  
  17.         method = demo.getMethod("sayHello"new Class[]{String.classint.class});  
  18.         method.invoke(demo.newInstance(), new Object[]{"Rollen"20} );  
  19.     }   
  20.     catch (Exception e)   
  21.     {  
  22.         e.printStackTrace();  
  23.     }  
  24. }  
打印结果:
hello ,china
Rollen  20


11、通过反射操作属性
正常情况下,我们是不可以直接操作其它某个对象的私有属性,但是反射可以做到
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public static void main(String[] args) throws Exception {  
  2.        Class<?> demo = null;         
  3.          
  4.        Object obj = null;    
  5.          
  6.        demo = Class.forName("com.reflect.People");    
  7.          
  8.        obj = demo.newInstance();       
  9.          
  10.        Field field = demo.getDeclaredField("sex");     
  11.          
  12.        field.setAccessible(true);     
  13.          
  14.        field.set(obj, "男");      
  15.          
  16.        System.out.println(field.get(obj));   
  17. }  
打印结果:


12、通过反射取得并修改数组的信息
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public static void main(String[] args) {  
  2.        int[] temp={1,2,3,4,5};    
  3.          
  4.        Class<?>demo=temp.getClass().getComponentType();    
  5.          
  6.        System.out.println("数组类型: "+demo.getName());   
  7.          
  8.        System.out.println("数组长度  "+Array.getLength(temp));    
  9.          
  10.        System.out.println("数组的第一个元素: "+Array.get(temp, 0));    
  11.          
  12.        Array.set(temp, 0100);           
  13.          
  14.        System.out.println("修改之后数组第一个元素为: "+Array.get(temp, 0));   
  15.          
  16. }  
打印结果:
数组类型: int
数组长度  5
数组的第一个元素: 1
修改之后数组第一个元素为: 100
0 0
原创粉丝点击