反射详解

来源:互联网 发布:畅捷通软件介绍 编辑:程序博客网 时间:2024/06/06 00:20

反射技术==>动态加载一个指定的类.获得该类的字节码文件对象-->获得该类中所有的内容.-->对类进行解剖

1.类的初始化:

    类的初始化:就是类的加载,将类从硬盘放到内存中.

    时机:什么时候使用到这个类,加载器就会将该类加载到内存中.

1.创建类的实例

2.类的静态变量,或者为静态变量赋值

3.类的静态方法

4.使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

5.初始化某个类的子类

6.直接使用java.exe命令来运行某个主类

 

 

2.类的加载器: -->(原理:就是按照一定的格式将硬盘上的文件读入到内存中)

负责将.class文件加载到内在中,并为之生成对应的Class对象。

虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行

    Bootstrap ClassLoader根类加载器.==>也叫引导类加载器

        加载核心类库...System,String...主要是\lib\rt.jar

    Extension ClassLoader扩展类加载器==>

        扩展类加载器,目前只要加载src\lib\ext文件夹.

    System ClassLoader系统类加载器

        主要是加载用户自定义的,或者用户导入的第三方jar.

3.如何获得Class文件对象,字节码文件对象.

    1.通过该类的对象,直接获得:

         Class clazz = obj.getClass(); ==>必须创建该类的对象.

    2.通过类中的静态方法或者静态的成员变量.静态的属性class.

    3.使用Class类中的方法.

         Class clazz = Class.forName(classname);

 

注意:第三种和前两种的区别前两种你必须明确Person类型.后面是指定这种类型的字符串就行.这种扩展更强.我不需要知道你的类.我只提供字符串,按照配置文件加载就可以了

 

4. 反射的使用步骤:    

    1.获得指定类的Class文件对象,(获得字节码文件对象)

    2.实例化对象,获得类的属性,方法或构造方法.

    3.访问属性,方法,调用构造方法创建对象.

5.反射的用法:

    1.获得Class文件的对象.

        ★★Class clazz = Class.forName(classname);用于类加载.

                   classname需要全名..eg:com.mysql.jdbc.Driver  -->不可以带class后缀.

         Class clazz = Person.class             类名获取.

          Class clazz = p.getClass()         类对象直接获取.

       快速创建对象:

              1.类需要有空参构造

              2.该空参构造权限需要是public

                   Object obj =clazz.newInstance();

                   直接通过clazz文件对象创建对象,底层就是使用类的空参获得的实例.

     2.反射类的构造方法:

         Constructor con =clazz.getConstructor(Class<?>... params );//只能获得public修饰的.

              获得任意一个公有的指定参数列表的构造,如果不指定参数,获得的就是空参构造.

         Constructor con =clazz.getDeclareConstructor(Class<?>... params );//可以获得私有的构造

              获得任意一个(包括私有的)指定参数列表的构造,如果不指定参数,获得的就是空参构造.

         Constructor[] cons= clazz.getDeclareConstructors(Class<?>... params );//可以获得私有的构造

              获得该类中的所有的(包括私有的)构造方法.  

         通过对象的构造器,获得该类的实例对象:

              Object obj =con.newInstance(Object ... params); //参数传递,是根据使用的构造方法的参数列表来确定.

    3.反射类的属性.

         Field field = clazz.getField(String name);

              //获得指定名称的属性字段对象.只能是public修饰的

         Field[] fields = clazz.getDeclareFields();//无需名称.

              获得该类中以及父类或者接口中继承的所有字段,包括私有的.

         field.setAccessable(true);//取消访问权限.

         field.set(Object obj,Object value); //设置obj对象的该field字段的值为value.

     

    4.反射类的方法.

         Method[] methods = clazz.getDeclareMethods();

              //返获得该类中所有的方法,包括私有的.

              返回 Method对象的一个数组,这些对象反映此Class对象表示的类或接口声明的所有的方法,

              包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法.

         Method method = clazz.getDeclareMethod(Stringmethodname,Class<?>...params);

              获得一个指定名称的方法.参数为该方法的参数类型的class文件.

         method.setAccessable(true);

         method.invoke(Object obj,params);

              -->调用obj对象中的method方法.传入的参数为params.(需要和前面获得的方法的参数列表相同.)

          

 

反射的应用:

    1.泛型擦除.

    定义泛型限制的集合,向其中存入非泛型限定的数据类型.

     

 *分析:

 * 1.要想在一个指定泛型(Integer类型)list集合中存入一个String类型的对象,就需要使用到反射技术.

 * 2.考虑到list添加元素的方法是add.因此,准备使用add方法进行反射添加.

     ArrayList<Integer>list=newArrayList<Integer>();

     //第一步,获得该对象的字节码文件.

    Classc=list.getClass();

   //第一个参数,是方法名.第二个参数是参数类型的字节码文件.

    Methodmethod=c.getDeclaredMethod("add",Object.class);//获得该类的add方法

   method.setAccessible(true);//取消访问限制

     method.invoke(list,"我是字符串,就要加进来,气死你!");





使用代码进行测试:

/** * 自定义一个测试类 * @author myth * */public class User {//私有属性.private String name;private String sex;//一个方法public void  say(String exten) {System.out.println("你好:"+name+"附加字符为  :"+exten);}//构造默认为无参的.public User(){} //可以不声明的.}


用于测试用的类


反射的代码:

/** * 这个测试,是为了说明,有了反射,有了对应类的全路径. * 我们可以获得该对象的所有的字段,方法.以及构造.(包括私有的.) * 并且,我们可以暴力反射,即使该类没有指定对应的get/set方法,我们也可以去设置值. * @author myth * */public class ProxyTest {@Testpublic void test() throws Exception {//获得该类的字节码文件对象.Class clazz = Class.forName("com.myth.proxy.User");//通过该类的空参构造一个对象.没有空参,这个方法就会报错.User user = (User) clazz.newInstance();//获得所有的属性字段.包括私有的.Field[] declaredFields = clazz.getDeclaredFields();//遍历所有字段.for (Field field : declaredFields) {//因为想对name字段赋值.所以对字段进行判断.if ("name".equals(field.getName())) {//暴力反射,否则无法设置参数.因为该字段声明是私有的.field.setAccessible(true); field.set(user, "二哈"); //设置对应字段的值.//该语句类似于 user.setName("二哈");但是我们并没有提供get/set方法的.}}//获得对应方法名称的方法.(方法也是一个Method类的对象.)
//通过匹配方法名,得到一个唯一方法对象.Method method = clazz.getDeclaredMethod("say",String.class);//System.out.println(method);//public void com.myth.proxy.User.say(java.lang.String)//System.out.println(method.getName()); //saymethod.invoke(user, "哈哈");}}




原创粉丝点击