Java反射剖析

Java反射

一、Annotation的原理解析

 https://www.cnblogs.com/peida/archive/2013/04/24/3036689.html

二、调用构造函数

1.     走读API

在Class类中提供一下的操作方法:

取得全部构造:

publicConstructor<?>[] getConstructors()

       throws SecurityException

 

取得指定参数类型的构造:

publicConstructor<T> getConstructor(<?>...parameterTypes)

       throws NoSuchMethodException,

              SecurityException

 

在反射过程中是一个只认识类型不认具体对象的工具类,以上方法返回的是

java.lang.reflect.Constructor,这个类有如下方法:

取得构造方法的名称:publicString getName()

取得构造方法的修饰符:publicint getModifiers()

 

但是所有修饰符都是通过数字编号取得的,即如果想要取得具体的内容必须将相应的数字转为关键字,可以使用“java.lang.reflect.Modifier”类完成,这个类中提供了简单的方法使数字编号转为具体的关键字:public static String toString(int mod);

 

2.     实例代码1(获取全部,不指定参数)

package cn.km;

import java.io.ObjectStreamException;

import java.lang.reflect.Constructor;

import java.lang.reflect.Modifier;

class Book {

    private String title;

    private Double price;

   

    public Book(String title) throwsRuntimeException, NullPointerException,ObjectStreamException {

        this.title = title;

    }

   

    public Book(String title,Double price){

        this.title = title;

        this.price = price;

    }

   

    @Override

    public String toString() {

        return"书名: " + this.title + ",价格:" + this.price ;

    }

}

 

 

publicclassTestDemo {

    publicstaticvoid main(String[] args) throwsException{

        Class<?> cls =Class.forName("cn.km.Book");

       

        Constructor<?> cons[] = cls.getConstructors();//取得全部构造

       

        for(inti = 0; i < cons.length; i++){

            System.out.print(Modifier.toString(cons[i].getModifiers())+ "  "); //获取构造函数修饰符

            System.out.print(cons[i].getName()+ "("); //获取构造函数名

 

            Class<?>params[] = cons[i].getParameterTypes();

            for(intj = 0; j < params.length; j++){

                System.out.print(params[j].getSimpleName()+ " arg" + j);

                if(j < params.length - 1){

                    System.out.print(", ");

                }

            }

            System.out.print(") ");

           

            Class<?>exp[] = cons[i].getExceptionTypes(); //取得全部异常信息

            if(exp.length > 0){

                System.out.print(" throws ");        

                for(intx = 0; x < exp.length; x++){

                    System.out.print(exp[x].getSimpleName());

                    if(x < exp.length - 1){

                        System.out.print(" , ");

                    }

                }

            }

            System.out.println();

        }

    }

       

}


 

 

3.     示例代码2(指定参数)

package cn.km;

import java.io.ObjectStreamException;

import java.lang.reflect.Constructor;

import java.lang.reflect.Modifier;

class Book2 {

       privateString title;

       privateDouble price;

      

       Public Book2(String title,Double price)throws RuntimeException, NullPointerException,ObjectStreamException{

              this.title= title;

              this.price= price;

       }

      

       @Override

       publicString toString() {

              return "书名: " + this.title + ", 价格:" + this.price ;

       }

}

public class getConstructorsWithPara {

       publicstatic void main(String[] args) throws Exception{

              Class<?> cls =Class.forName("cn.km.Book2");

              Constructor<?>cons = cls.getConstructor(String.class,Double.class); //取得指定参数构造

              Book2 book2 = (Book2)cons.newInstance("java develop",79.6);

              System.out.println(book2);

       }

}


 

 

三、调用普通函数

1.     走读API

清楚了构造函数的调用之后,继续普通函数,在Class类里面提供了两组普通函数获取的方法:

第一组方法:

|-public 方法[] getDeclaredMethods() throwsSecurityException

|-public 方法 getDeclaredMethod(String name,类<?>... parameterTypes)

                         throwsNoSuchMethodException,

                                SecurityException

 

第二组方法:

|-public 方法[] getMethods() throwsSecurityException

|-public 方法 getMethod(String name,类<?>... parameterTypes)

                 throws NoSuchMethodException,

                        SecurityException

 

2.     实例代码3(getMethods和getDeclaredMethods比较)

package cn.km.method;

 

import java.lang.reflect.Method;

 

interface Message{

   publicvoid print();

}

abstractclass Info{

   publicabstractvoid get();

}

 

class MessageImpl extends Info implements Message{

 

   @Override

   publicvoid print() {} //覆盖接口中的方法

   @Override

   publicvoid get() {} //继承抽象类的方法

   publicvoid set() {} //定义自己的方法

  

}

 

publicclass TestDemo {

   publicstaticvoid main(String[] args) throws ClassNotFoundException {

      Class<?> cls = Class.forName("cn.km.method.MessageImpl");

      Method met[] = cls.getMethods();

      for(inti = 0; i < met.length; i++){

         System.out.println(met[i]);

      }

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

      Method met2[] = cls.getDeclaredMethods();

      for(inti = 0; i < met2.length; i++){

         System.out.println(met2[i]);

      }

   }

}


 

输出结果

 

 

使用getMethods获取的

使用getDeclaredMethods获取的是本类中定义的所有操作方法,与继承无关。。

 

以上的代码是利用了Method类之中的toString()方法取得了每一个方法的信息,现在要获取完整的方法信息,

取得方法的返回值类型:public 类<?> getReturnType()

取得方法的参数类型:public 类<?>[] getParameterTypes()

取得方法的异常信息:public 类<?>[] getExceptionTypes()

 

 

 

3.     实例代码4(获取方法的修饰符、参数类型、异常信息)

package cn.km.method;

 

import java.lang.reflect.Method;

import java.lang.reflect.Modifier;

import java.lang.reflect.Type;

 

interface Message{

   publicvoid print();

}

abstractclass Info{

   publicabstractvoid get(String name,Integer age);

}

 

class MessageImpl extends Info implements Message{

 

   @Override

   publicvoid print() {} //覆盖接口中的方法

   @Override

   publicvoid get(String name,Integer age) {} //继承抽象类的方法

   public String set(String name) throws Exception,NullPointerException{

      returnnull;

   }//定义自己的方法

  

}

 

publicclass TestDemo {

   publicstaticvoid main(String[] args) throws ClassNotFoundException {

      Class<?> cls = Class.forName("cn.km.method.MessageImpl");

      Method met[] = cls.getDeclaredMethods();

      for(inti = 0; i < met.length; i++){

         System.out.print(Modifier.toString(met[i].getModifiers()) + "  "); //获取方法修饰符

         System.out.print(met[i].getReturnType().getSimpleName()+"  ");

         System.out.print(met[i].getName() + "  ( ");

        

         //获取参数类型

         Class<?>paramTypes[] = met[i].getParameterTypes();

         for(intj = 0 ; j < paramTypes.length; j++){

            System.out.print(paramTypes[j].getSimpleName() + " arg" + j);

            if(j < paramTypes.length - 1){

               System.out.print(" , ");

            }

         }

         System.out.print(" )");

        

         //获取抛出的异常信息

         Class<?>exceptions[] = met[i].getExceptionTypes();

         if(exceptions.length > 0){

            System.out.print(" throws ");

            for(intt = 0; t < exceptions.length; t++){

               System.out.print( exceptions[t].getSimpleName() );

               if(t < exceptions.length - 1){

                  System.out.print(" , ");

               }

            }

         }

         System.out.println();

      }

   }

}


 

 

在Method中提供了一个比较重要的方法:

调用本类的invoke方法:

public Object invoke(Object obj,Object...args)

              throws IllegalAccessException,

                     IllegalArgumentException,

                     InvocationTargetException

 

在使用invoke方法的时候,一定要保证已经存在了本类的实例化对象,而方便的是,这个实例化对象可以是Object

可以直接利用Class类反射的实例化对象,而后通过Object类对象操作。而没有必要向下转型。。

 

4.     实例代码5(invoke无返回值)

package cn.km.method;

 

import java.lang.reflect.Method;

import java.lang.reflect.Modifier;

import java.lang.reflect.Type;

 

class Message{

   publicvoid echo(String str){

      System.out.println(str);

   }

}

 

publicclass TestDemo {

   publicstaticvoid main(String[] args) throws Exception {

      Class<?> cls = Class.forName("cn.km.method.Message");

      Object object =  cls.newInstance();

      Method method = cls.getDeclaredMethod("echo", String.class);

      method.invoke(object, "nihao !");

   }

}


 

 

5.     实例代码6(invoke 有返回值)

package cn.km.method;

 

import java.lang.reflect.Method;

import java.lang.reflect.Modifier;

import java.lang.reflect.Type;

 

class Message{

   public String echo(String str){

      return"echo: " + str;

   }

}

 

publicclass TestDemo {

   publicstaticvoid main(String[] args) throws Exception {

      Class<?> cls = Class.forName("cn.km.method.Message");

      Object object =  cls.newInstance();

      Method method = cls.getDeclaredMethod("echo", String.class);

      String result = (String) method.invoke(object, " nihao !");

      System.out.println(result);

   }

}


 

 

在实际的代码中,简单java类之中的属性一定要进行封装、封装后的属性要按照指定的要求编写setter,getter

6.     实例代码7(利用反射实现getter,setter调用)

package cn.km.method;

 

import java.lang.reflect.Method;

importcom.sun.xml.internal.ws.util.StringUtils;

class Dept{

   private String dname;

   public String getDname() {

      returndname;

   }

   publicvoid setDname(String dname) {

      this.dname = dname;

   }

}

publicclass TestDemo {

   publicstaticvoid main(String[] args) throws Exception {

      String className = "cn.km.method.Dept";

      String property = "dname";

      String value = "development";

      Class<?> cls = Class.forName(className);

      //获取get方法

      Method setter = cls.getDeclaredMethod("set" + StringUtils.capitalize(property), String.class);

      //获取set方法

      Method getter = cls.getDeclaredMethod("get" + StringUtils.capitalize(property));

      Object object =  cls.newInstance();

      //执行set方法

      setter.invoke(object, value);

      //执行get方法     

      System.out.println(getter.invoke(object));

   }

}

上面有一个小的缺陷就是需要指定set的参数类型。。。。

四、调用成员

一个类中可以定义的成员:全局常量、全局变量、普通常量、普通变量,在Class类中提供了两组取得成员的方法:

第一组:

public 字段[] getFields() throws SecurityException

public 字段 getField(String name)

throws NoSuchFieldException,SecurityException

第二组:

public 字段[] getDeclaredFields() throws SecurityException

public 字段 getDeclaredField(String name)

throws NoSuchFieldException,SecurityException

五、其他

1.     StringUtils.capitalize(Stringarg0)

把字符串的首字母大写。如果你传入的字符串首字符本身就是大写,不作任何改变。。

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值