Java反射技术


java的反射机制:

          我们都知道,一个java类中,有成员变量、成员方法、构造方法等等,反射机制,就是动态的获取这些类中的信息,并动态的调用对象的方法。通常只有要设计框架的过程中,才会使用java反射相关的api,但是了解java反射机制的基本原理与基本方法,可以帮忙我们在日后对框架的学习与应用提供很大的帮忙。
反射的使用,简单的讲,就是通过类的Class对象,获取对应的Field、Method 和 Constructor 对象并进行相关操作。通常jdk中的关于反射的api我们一般使用与框架的编写。

1获得类的字节码文件的三种方法
<span style="font-size:18px;">package com.reflect;

import com.reflect.bean.Person;

/**
 * User: OF895
 * Date: 14-11-11
 * Time: 下午1:43
 */
public class GetClazzDemo {
    public static void main(String[] args) {

        //反射,加载类,获得类的字节码文件
        try {
            //第一种获得“类的字节码”文件的方法,将类的字节码文件加载到"内存中"
            Class clazz = Class.forName("com.reflect.bean.Person");
            System.out.println(clazz);
            //第二种获得“类的字节码”文件的方法
            Class clazz1 = new Person().getClass();
            System.out.println(clazz1);
            //第三种获得“类的字节码”文件的方法,将类的字节码文件加载到内存中
            Class clazz2 = Person.class;
            System.out.println(clazz2);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
</span>

2利用反射技术反射出类中的方法的构造函数
Person类,用于被反射的类:
<span style="font-size:18px;">package com.reflect.bean;

import java.io.InputStream;
import java.util.List;

/**
 * User: OF895
 * Date: 14-11-11
 * Time: 下午1:44
 */
public class Person {
    public int age;
    public String name = "小明";
    public String height = "100";
    private String gender = "男";
    public static String weight = "300";

    //私有的构造方法
    private Person(List<String> list) {
        System.out.println("这个一个私有的构造方法!");
    }

    public Person() {
        System.out.println("new person!");
    }

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
        System.out.println("这是含有参数的构造方法!");
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    public void say() {
        System.out.println("这是一个不带参数的say方法!");
    }

    public void say(String name, int age) {
        System.out.println(name + ":" + age);
    }

    public Class[] say(String name, int[] password) {
        return new Class[]{String.class, int.class};
    }


    private void say(InputStream in) {
        System.out.println(in);
    }

    //静态方法的反射
    public static void say(int num) {
        System.out.println(num);
    }

    //如何反射main方法,注意一下main方法的参数是一个String类型的数组
    public static void main(String[] args) {
        System.out.println("main...................");
    }
}
</span>




<span style="font-size:18px;">package com.reflect;

import com.reflect.bean.Person;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

/**
 * 利用反射技术反射出类中的方法的构造函数
 * User: OF895
 * Date: 14-11-11
 * Time: 下午5:35
 */
public class GetConstructDemo {

    //反射类中的无参数的构造方法
    @Test
    public void test1() {
        try {

            Class clazz = Class.forName("com.reflect.bean.Person");
            //反射类中的无参数的构造方法
            Constructor constructor = clazz.getConstructor(null);
            //构造函数的主要作用是实例化一个对象,所以在这里我们拿到一个Constructor对象后,我们可以通过调用他的newInstance()方法,实例化一个对象!
            Person person = (Person) constructor.newInstance();
            System.out.println(person.height);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    //反射类的含有参数的构造方法
    @Test
    public void test2() throws Exception {
        Class clazz = Class.forName("com.reflect.bean.Person");
        //反射类中含有参数的构造方法,这里不要写成Integer.class,int.class
        Constructor constructor = clazz.getConstructor(int.class, String.class);
        Person person = (Person) constructor.newInstance(20, "xiaoming");
        person.say();
    }

    //反射类中的私有的的构造方法
    @Test
    public void test3() throws Exception {
        Class clazz = Class.forName("com.reflect.bean.Person");
        //反射类中的私有的构造方法
        Constructor constructor = clazz.getDeclaredConstructor(List.class);
        //不管被反射的类的构造方法是什么样的访问权限,这里强制允许访问,如果这里不这样设置,那么在类外是无法访问Person类的“私有的”构造方法的。
        constructor.setAccessible(true); //反射类的私有的构造函数,那么这个设置一定要加上!
        Person person = (Person) constructor.newInstance(new ArrayList());
    }


    //反射类,创建类的对象的另外一种方法
    @Test
    public void test4() throws Exception {
        Class clazz = Class.forName("com.reflect.bean.Person");
        //通过clazz类的newInstance()方法我们也可以直接反射出类的对象
        //与上面的例子区别开来,原理:其实这个类的源码也就是先反射出一个无参数的Constructor对象
        //然后再通过这个Constructor的newInstance()方法得到
        //这个就是sun公司给我们提供的一种简便的方法
        Person person = (Person) clazz.newInstance();
    }

}
</span>


3利用反射技术去反射类的“方法”(这里被反射的类,仍然使用的是例子2中的Person对象)
<span style="font-size:18px;">package com.reflect;

import com.reflect.bean.Person;
import org.junit.Test;

import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;

/**
 * 利用反射技术去反射类的“方法”
 * User: OF895
 * Date: 14-11-11
 * Time: 下午10:09
 */
public class GetMethodDemo {

    /**
     * public void say() {
     * System.out.println("这是一个不带参数的say方法!");
     * }
     *
     * @throws Exception
     */
    //反射“无参数”的方法
    @Test
    public void test1() throws Exception {
        Class clazz = Class.forName("com.reflect.bean.Person");
        //因为在下面使用invoke方法的时候,我们需要指定反射那个对象下面的那个方法,所以我们需要先“反射”出一个对象!
        Person p = (Person) clazz.newInstance();
        //查阅api可以知道第一个参数是“方法名”,第二个参数是方法的参数类型
        Method method = clazz.getMethod("say", null);//得到无参数的方法的Method对象
        //查阅api可以看到,在调用invoke方法的时候,我们必须要执行我们要
        method.invoke(p, null);
    }

    //反射“带参数”的方法

    /**
     * public Class[] say(String name, int[] password) {
     * return new Class[]{String.class, int.class};
     * }
     *
     * @throws Exception
     */
    @Test
    public void test2() throws Exception {
        Class clazz = Class.forName("com.reflect.bean.Person");
        //因为在下面使用invoke方法的时候,我们需要指定反射那个对象下面的那个方法,所以我们需要先“反射”出一个对象!
        Person p = (Person) clazz.newInstance();
        Method method = clazz.getMethod("say", String.class, int[].class);
        //这里注意一下“反射”的方法的返回类型是Class[]类型的,字节码类型的数组!
        Class[] array = (Class[]) method.invoke(p, "小明", new int[]{1, 2, 3});
        System.out.println(array.length);
    }


    /**
     * 要反射的方法:
     * private void say(InputStream in) {
     * System.out.println(in);
     * }
     *
     * @throws Exception
     */
    @Test
    public void test3() throws Exception {
        Class clazz = Class.forName("com.reflect.bean.Person");
        //因为在下面使用invoke方法的时候,我们需要指定反射那个对象下面的那个方法,所以我们需要先“反射”出一个对象!
        Person p = (Person) clazz.newInstance();
        //注意一下要“反射”方法的参数的类型是InoutStream类型的
        Method method = clazz.getDeclaredMethod("say", InputStream.class);
        //因为要反射的方法是“private”类型的,所以这里需要设置一下可访问性!
        method.setAccessible(true);
        //第一个参数是要反射的对象,第二个参数是要反射对象的方法的参数
        method.invoke(p, new FileInputStream("d://test.txt"));
    }

    /**
     * //静态方法的反射
     * public static void say(int num) {
     * System.out.println(num);
     * }
     */
    @Test
    public void test4() throws Exception {
        Class clazz = Class.forName("com.reflect.bean.Person");
        Method method = clazz.getMethod("say", int.class);
        //反射静态方法有个不同的地方就是,进行方法在调用的时候是不需要传入对象的,所以前面给null就可以了!
        method.invoke(null, 20);
    }


    /**
     *如何反射main方法?这个有点特殊,不能直接在invoke的时候传入String[]类型的参数
     * 这里jdk1.5之后才出现了“可变参数”的概念,sun公司为了兼容以前的代码,这里做了一个折中的选择。
     */
    @Test
    public void test5() throws Exception {
        Class clazz = Class.forName("com.reflect.bean.Person");
        Method method = clazz.getMethod("main", String[].class);
        //这个有点特殊,不能直接在invoke的时候传入String[]类型的参数,必须传入new Object[]{new String[]{"hello","world"}}
        //如果直接传入new String["hello","world"],会在person中去寻找有两个String类型的static的main方法,它默认会将String["hello","world"]拆成"hello","world两个参数
        method.invoke(null, new Object[]{new String[]{"hello","world"}});
    }

}
</span>

4反射类的“字段”(这个仍然是是使用上面的Person类)
<span style="font-size:18px;">package com.reflect;


import com.reflect.bean.Person;
import org.junit.Test;

import java.lang.reflect.Field;

/**
 * 反射类的“字段”
 * User: OF895
 * Date: 14-11-11
 * Time: 下午11:26
 */
public class GetFieldDemo {

    /**
     * 反射Person类的name字段
     * <p/>
     * public String name = "小明";
     */
    @Test
    public void test1() throws Exception {
        Class clazz = Class.forName("com.reflect.bean.Person");
        //这里的参数是要“反射的”字段的“引用名”
        Field field = clazz.getField("name");
        //我们可以获取到“反射的”字段的“类型”
        Class type = field.getType();
        //获取到“反射的”字段的值,参数一定要记住,要从“反射那个对象”中的此字段,要传入“被反射字段所在的类的对象”
        Person p = (Person) clazz.newInstance();
//        Object value = field.get(p);
        if (type.equals(String.class)) {
            //我们还可以为“字段”赋值,先赋值,在取值
            field.set(p,"科比");
            //这里的字段P,指的是反射的“字段”,所在的类的"对象"
            Object value = field.get(p);
            //如果得到的“反射的字段”的类型是java.lang.String类型的,那么我们就将“反射的”字段的值,强制转换成String类型的
            String str = (String) value;
            System.out.println(str);
        }
    }


    /**
     * 反射私有的字段
     *  private String gender = "男";
     *
     */
    @Test
    public void test2() throws Exception {
        Class clazz = Class.forName("com.reflect.bean.Person");
        Field field = clazz.getDeclaredField("gender");
        field.setAccessible(true);
        Object value = field.get(clazz.newInstance());
        System.out.println(value);
    }

    /**
     *
     * 反射类的静态的字段
     *
     *   public static String weight = "300";
     */

    @Test
    public void test3() throws Exception {
        Class clazz = Class.forName("com.reflect.bean.Person");
        Field field = clazz.getDeclaredField("weight");
        //由于“反射的”是“静态的”字段,所以我们不需要指定反射的具体的类的对象,因为这个类的这个静态的“字段”在内存中只有一份,是通用的。
        Object value = field.get(null);
        System.out.println(value);
    }
}</span>



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值