反射的基本使用

在使用之前我们先想一下反射的作用,网上各种解读比较多,我认为反射的作用就是,当无法直接使用一个类的属性,构造器,方法时,我们通过反射来实现,反射可以获得一个类的所有信息。比如你想调用某个API,但是这个API在源码里用了@hide来标注,这时我们就用反射间接的来使用这个API。

使用反射有两个大的步骤,一是获取该类对应的字节码文件,即Class对象,二是获取该类的信息,即属性,方法,构造器。当然除了获取,我们也可以调用。比如我们这里有一个Person类,我们用反射来获取它的各种信息。

package com.xn.reflect;

public class  Person{
    public int age;

    public String name;

    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 Person(int age, String name) {
        super();
        this.age = age;
        this.name = name;
    }

    public Person() {
        super();
    }

    public void method1() {
        System.out.println("this is method1");
    }

    public void method2() {
        System.out.println("this is method2");
    }
}

一:获取Class对象

1.1 、通过Object.getClass()方法
   /**
     * 第一种获取Class对象的方法,Object的getClass方法
     */
    public static Class getClass1(){
        Person person=new Person();
        Class class1 = person.getClass();
        return class1;
    }
1.2、通过Object类的静态属性来获取
    /**
     * 第二种获取Class对象的方法,通过Object的静态属性来获取
     */
    public static Class getClass2(){
        Class class1 = Person.class;
        return class1;
    }
1.3、通过Class的静态方法来获取
   /**
     * 第三种获取Class对象的方法,通过Class的静态方法来获取
     */
    public static Class getClass3(){
        Class class1;
        try {
            class1 = Class.forName("com.xn.reflect.Person");
            return class1;
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;

    }

我们打印一下,看是否得到的同一个对象。

public static void main(String[] args) {
        System.out.println(getClass1()==getClass2());
        System.out.println(getClass2()==getClass3());
    }

打印结果如下:true true

二:获取该类的信息(属性,构造器,方法)

这里有个技巧就是通过getXXX,获取的都是共有的,即用public ,protect声明的,若要是获取私有的属性,,方法,构造器,我们就要使用getDeclaredXXX来获取。

2.1、获取类的构造器,并通过构造器来获取类的实例

有两种方式来获取,实际上可以通过Class的方法newInstance方法和通过构造器对应的类Constructor来获取,但是newInstance这个方式是用无参的构造函数来获取实例的。如果是有参的函数则要通过Constructor的方法来获取,下面直接上代码。注释也比较解释得比较详细。

    /**
     * 使用反射得到构造器,一般我们使用构造函数来获取该的实例
     */
    public static void getConstruct() {
        Class clazz=null;
        try {
            //第一种方式,当构造函数是无参的时候
            //得到Person对应的字节码对象
             clazz = Class.forName("com.xn.reflect.Person");
            //通过newInstance()方法得到,默认是调用该类的无参的构造方法,如果当我们的
            Person person = (Person) clazz.newInstance();
            //第二种方式,当构造函数是有参的时候
            Class[]clazzs={int.class,String.class};
            Constructor constructor = clazz.getConstructor(clazzs);
            Person p1=(Person) constructor.newInstance(new Object[]{"","喝喝"});
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
2.2、通过反射获取该类所声明的属性

可以通过反射来获取该类属性,即使是用private声明的私有属性都可以获取得到。同样是先获取字节码的对象然后,获取属性,进而获取属性的值.

/**
     * 使用反射机制来获取类 的属性
     */
    public static void getField(){
        try {
            //获得字节码文件
            Class clazz = Class.forName("com.xn.reflect.Person");
            Field field = clazz.getDeclaredField("age");
            //暴力访问,忽略权限控制符
            field.setAccessible(true);
            //获取类对象
            Object object=clazz.newInstance();
            //为属性赋值
            field.setInt(object, 24);
            Object o=field.get(object);
            System.out.println(o);
        } catch (Exception e) {

            e.printStackTrace();
        }
    }

我们这里做的操作是这样的,首先获取字节码对象,然后获取该类的对象,再获取该类的属性,我们给属性赋值,再把属性打印出来,最后调试的结果是24。
我们要注意的是getDeclaredField该方法是Field及Method及Constructor的父类对应的方法,setAccessible(boolean flag) 是表示访问忽略访问控制符,调用之后可以访问私有的,也就是private修饰的方法或属性,Method也是一样。

2.3、通过反射来获取方法,并进行调用。
    /**
     * 通过反射来获取的方法,并进行调用
     */
    public static void getMethod(){

        //获得字节码文件
        try {
            Class clazz = Class.forName("com.xn.reflect.Person");
            Method method = clazz.getDeclaredMethod("method1", null);
            method.setAccessible(true);
            Object obj=clazz.newInstance();
            method.invoke(obj, null);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

注意的一点就是获取方法的时候,和调用的时候,要传入参数列表,要是没有就传null,见上面的clazz.getDeclaredMethod(“method1”, null),这里传的是参数类型的字节码对象,和method.invoke(obj, null)这里传的是实参。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值