Java 反射机制介绍

href="file:///C:/DOCUME~1/others/LOCALS~1/Temp/msohtml1/01/clip_filelist.xml" rel="File-List" />

Java 反射机制

1.介绍

Java 的反射机制是使其具有动态特性的非常关键的一种机制,通过java反射机制,可以动态分析一个类的属性及行为,也是在JavaBean 中广泛应用的一种特性。

2Class类介绍

Java的反射机制是通过对Class类的操作进行的,在程序运行期间,运行时系统始终为所有的对象维护一个被称为运行时的类型标识,这个信息保存着每个对象所属的类足迹。

3. 获取Class

获取Class类有三种方法,下面分别介绍:

(1)       调用一个类对象的getClass方法,将返回这个对象所属类的Class类型。

(2)       调用Class类的forName方法,它的参数是一个字符串,当字符串代表的不是一个类或接口的时候,调用forName方法会抛出一个checkedexception。所以无论何时使用这个方法都应该提供一个异常处理。

(3)       如果T代表任意Java类型(T即可以是类也可以是基本的数据类型)。

如:Class class1 = int.class;(基本数据类型)

     Class class2 = Date.class;(类)

     Class class3 = int[].class;(类)

 

ClassnewInstance()方法,作用是返回这个类的一人实例,由于这个方法没有提供参数,所以构造类对象时是调用的相应类的默认构造方法。在这时一定要注意异常处理,测试代码如下:

package reflect;

 

public class SampleReflect {

    public String info;

 

    /**

     * @return the info

     */

    public String getInfo() {

       return info;

    }

 

    /**

     * @param info the info to set

     */

    public void setInfo(String info) {

       this.info = info;

    }

   

    /**print Info

     *

     */

    public void printInfo() {

       System.out.println("Information : " + this.info);

    }

   

    public static void main(String[] arg) {

       Class cla1 = null;

       String classType = "reflect.SampleReflect";

       try {

           cla1 = Class.forName(classType);

       } catch (ClassNotFoundException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

           System.out.println("没有找到类 : " + classType);

       }

       System.out.println("第二种方法得到Class : " + cla1.getName());

       //调用方法printInfo

       SampleReflect sr1 = null;

       try {

           sr1 = (SampleReflect) cla1.newInstance();

       } catch (InstantiationException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

           System.out.println("不能实例化对象。/n请确认你要实例化的类不是一个抽象类或接口。");

       } catch (IllegalAccessException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

           System.out.println("发生对类非法访问的异常");

       }

       //调用SampleReflect类的printInfo方法

       sr1.setInfo("我是用ClassforName方法加载的");

       sr1.printInfo();

       //打印sr1.getClassgetNameSampleReflect.classgetName方法返回值

       System.out.println("第一种方法得到Class : " + sr1.getClass().getName() + "/n"

              + "第三种方法得到Class : " + SampleReflect.class.getName());

    }

}

4 利用反射分析类的能力

java.lang.reflect包中有三个类FieldmethodConstructor分别用于描述类的域、方法及构造器,且他们都有一个getName()方法用来返回相应项目的名称。Field类有一个getType方法,用来返回描述域所属类型的Class对象。这三个类还有一个getModifiers的方法,返回一个整数用于描述publicprivateprotected等描述。可以调用Modifier类相应静态方法来判断是什么修饰符。

Class类的getFiledsgetMethodsgetConstructorsgetDeclareFieldsgetDeclareMethodsgetDeclareConstructors的区别:前者返的都是用public修饰的项目,而后都返的全部项目,但想想也明白,不包括超类的项目。

下面的代码对main函数的第一个参数代表的类进行分析,并输出到控制台所有的域、构造器及方法。代码AnalyseClass如下:

package reflect;

 

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import java.lang.reflect.Modifier;

import java.lang.reflect.TypeVariable;

 

public class AnalyseClass {

 

 

    /**

     * @param cla

     */

    public AnalyseClass(Class cla) {

       this.cla = cla;

       this.printConstructors();

       this.printMethods();

       this.printFields();

    }

   

    //待分析的类

    Class cla = null;

   

    /**打印类声明的所有构造器

     * @return 声明的构造器的个数

     */

    public int printConstructors() {

       System.out.println("/n****constructors of Class " + this.cla.getName() + "****");

       Constructor[] cons = cla.getDeclaredConstructors();

       int counter = 0;

       for(Constructor c : cons) {

           ++counter;

           String name = c.getName();

           String modifiers = Modifier.toString(c.getModifiers());

           if(modifiers.length() > 0) {

              System.out.print(modifiers + " " + name + "(");

           }

           Class[] types = c.getParameterTypes();

           for(int j = 0;j < types.length; ++j) {

              if(j > 0) System.out.println(",");

              System.out.print(types[j].getName());

           }

           System.out.println(");");

       }

       return counter;

    }

   

    /**打印类声明的所有方法

     * @return 声明的方法的个数

     */

    public int printMethods() {

       System.out.println("/n****methods of Class " + this.cla.getName() + "****");

       Method[] methods = cla.getDeclaredMethods();

       int counter = 0;

       for(Method m : methods) {

           ++counter;

           String name = m.getName();

           String modifiers = Modifier.toString(m.getModifiers());

           if(modifiers.length() > 0) {

              System.out.print(modifiers + " " + name + "(");

           }

           Class[] types = m.getParameterTypes();

           for( int j = 0; j < types.length; ++j) {

              if(j > 0 ) System.out.print(",");

              System.out.print(types[j].getName());

           }

           System.out.println(");");

       }

       return counter;

    }

   

    /**打印类声明的域

     * @return 声明的域的个数

     */

    public int printFields() {

       System.out.println("/n****fields of Class " + this.cla.getName() + "****");

       Field[] fields = cla.getDeclaredFields();

       int counter = 0;

       for(Field f : fields) {

           String name = f.getName();

           String modifiers = Modifier.toString(f.getModifiers());

           if(modifiers.length() > 0) {

              System.out.println(modifiers + " " + name + ";");

           }

           ++counter;

       }

       return counter;

    }

   

    public static void main(String[] args) {

       if(args.length > 0) {

           Class cla = null;

           try {

              cla = Class.forName(args[0]);

           } catch (ClassNotFoundException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

              System.out.println("没有找到类 : " + args[0]);

              return;

           }

           new AnalyseClass(cla);

       }else {

           System.out.println("请附带类");

       }

    }

}

对于上述的分析类的程序,打印构造器、域及方法时可以直接调用相应的toString()方法。

5.执行方法

对于类SampleReflect加入下面测试代码,用Methodinvoke方法执行方法。

如果invoke的是一个静态方法,第一个隐式参数可以不写,但若不是静态方法时,第一个隐式参数就必须填了,为要执行的对象的object引用。

try {

           Method m1 =cla1.getMethod("setInfo",String.class);

           if(m1 != null) {

              m1.invoke(sr1, "通过Methodinvoke方法进行的调用");

           }

       } catch (SecurityException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

       } catch (NoSuchMethodException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

       } catch (IllegalArgumentException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

       } catch (IllegalAccessException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

       } catch (InvocationTargetException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

       }

}

 

6. 在运行时使用反射分析对象

   在编写程序时,如果知道要查看的域名和类型,查看指定的域是一件很容易的事情。而利用反射机制可以查看在编译时还不清楚的对象域。

主要使用了Field类的get(Object)方法,当Field为私有域时,会抛出IllegalAccessException。反射机制默认行为受限于java的访问控制。然而,如果一个java程序没有受到安全管理器的控制,就可以履盖访问控制。为了达到这个目的,需要调用Field MethodConstructor对象的setAccessible方法。

//访问控制

       Field f = null;

       try {

           f = cla1.getField("info");

f = cla1.getDeclaredField("info");

       } catch (SecurityException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

           System.out.println("非法访问");

       } catch (NoSuchFieldException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

           System.out.println("没有这个域");

       }

       if (f != null) {

           try {

              System.out.println("info的值为 : " + f.get(sr1));

           } catch (IllegalArgumentException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

           } catch (IllegalAccessException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

              System.out.println("不能访问");

           }

       }

由于域info的修饰符是public,故上面的代码可以成功运行。但如果把info变为private时,就会产生异常:NoSuchFieldException 。因为getField只能得到被声明为public的项目,故得不到info这个域。所以这里要用getDeclaredField方法来得到info域。

7.使用反射实现运算表达式的计算

代码如下:

import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.PrintWriter;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

 

import javax.tools.JavaCompiler;

import javax.tools.ToolProvider;

 

 

public class DyComp {

    String expr = null; 

//  private static com.sun.tools.javac.Main javac = new com.sun.tools.javac.Main();

   

    public static double execute(String expr) {

       DyComp dc = new DyComp(expr);

       double result = -99999;

       try {

           result = dc.result();

       } catch (IOException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

       }

       return result;

    }

   

    //私有构造

    private DyComp(String expr) {

       this.expr = expr;

    }

   

    public double result() throws IOException {

       String javafileContent = "import java.io.*;/r/n" +

              "public class ExpreDyComp {" + "/r/n" +

           "public static double cal() {/r/n" +

                  "/tdouble var = " + this.expr + ";/r/n" +

                  "return var;/r/n" +

                  "}/r/n}";

       System.out.println("待生成的文件内容" + "/n" + javafileContent);

       File tmpFile = new File("ExpreDyComp.java");

       tmpFile.createNewFile();

       PrintWriter printWriter = new PrintWriter(new FileWriter(tmpFile));

       printWriter.write(javafileContent);

       printWriter.flush();

       printWriter.close();

       //对文件进行编译

       JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

       int compRes = compiler.run(null, null, null,"-d","bin","ExpreDyComp.java");

       if(compRes != 0) {

           System.out.println("编译出错");

       }

      

       Class exprClass = null;

       try {

           exprClass = Class.forName("ExpreDyComp");

       } catch (ClassNotFoundException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

           System.err.println("找不到相应类");

       }

       Method m = null;

       try {

           if(exprClass != null) {

              m = exprClass.getMethod("cal");

           }

       } catch (SecurityException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

       } catch (NoSuchMethodException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

       }

       if(m != null) {

           try {

              Double d = (Double)m.invoke(null);

              //System.out.println("值为" + d.doubleValue());

              return d.doubleValue();

           } catch (IllegalArgumentException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

           } catch (IllegalAccessException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

           } catch (InvocationTargetException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

           }

       }

       return -9999;

    }

   

    private double readResultToFile(File inFile) throws IOException {

       BufferedReader bf = new BufferedReader(new FileReader(inFile));

       String content = bf.readLine();

       double res = 0;

       if(content != null) {

           res = Double.parseDouble(content);

       } else {

           System.out.println("文件" + inFile.getAbsolutePath() + "无数据");

       }

       bf.close();

       return res;

    }

   

    public static void main(String args[]) {

       System.out.println("动态编译");

       System.out.println("输入你要计算的表达式");

       InputStreamReader inputReader = new InputStreamReader(System.in);

       BufferedReader bfReader = new BufferedReader(inputReader);

       String expre = null;

       try {

           expre = bfReader.readLine();

       } catch (IOException e1) {

           // TODO Auto-generated catch block

           System.out.println("从键盘输入出现问题");

           e1.printStackTrace();

       }

       //定义结果数据

       double result = -99999;

       result = execute(expre);

       //打印到console

       System.out.println(expre + "计算结果如下" + "/n" + result);

    }

}

 

附:继承设计的技巧

1 将公共操作和域放在超类。

2.不要使用受保护的域。

3 使用继承实现is-a关系。

4 除非所有继承的方法都有意义,否则不要使用继承。

5 在履盖方法不要改变预期的行为。

6 使用类型信息而非类型信息。

7 不要过多的使用反射。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值