Java中的反射

Posted Beans_bag

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中的反射相关的知识,希望对你有一定的参考价值。

1、反射技术简介

Java反射技术应用广泛,它能够配置:类的全限定名、方法和参数,完成对象的初始化,甚至可以反射某些方法。这样就大大增强了Java的可配置性,Spring IOC的基本原理也是如此。

2、Java反射机制的定义

Java反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的属性和方法。对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态获取的信息以及动态调用方法的功能成为Java的反射机制。用一句话总结就是Java的反射机制可以在运行状态中知道任意一个类的属性和方法。

优点

通过配置就可以生成对象,可以解除程序的耦合性,非常灵活。而且在项目上线后,后期可以很方便的对项目功能进行更新。

缺点

运行慢,对程序的性能有一定的影响。因为使用反射基本上是一种解释性操作。这类操作总是慢于直接执行相同的操作。

3、Java类和类类型

类是java.lang.Class类的实例对象,而Class是所有类的类。对于普通的对象,我们一般都会这样创建和表示:

Person p = new Person();

上面说了,所有的类都是Class的对象,那么如何表示呢,可不可以通过如下方式呢:

Class clazz = new Class();

但是我们查看Class的源码时,是这样写的:

private Class(ClassLoader loader) {
        // Initialize final field for classLoader.  The initialization value of non-null
        // prevents future JIT optimizations from assuming this final field is null.
        classLoader = loader;
}

可以看到构造器是私有的,只有JVM可以创建Class的对象,因此不可以像普通类一样new一个Class对象,虽然我们不能new一个Class对象,但是却可以通过已有的类得到一个Class对象,共有三种方式,如下:

//这说明任何一个类都有一个隐含的静态成员变量class,这种方式是通过获取类的静态成员变量class得到的
Class clazz1 = Person.class;

//这种方式是通过一个类的对象的getClass()方法获得的
Person p = new Person();
Class<? extends Person> clazz2 = p.getClass();

//这种方法是Class类调用forName方法,通过一个类的全量限定名获得
Class<?> clazz3 = Class.forName("cn.zhuangxp.reflect.Person");

这里的clazz1、clazz2、clazz3都是Class对象,他们是完全一样的,而且有个学名,叫做Person的类类型。类类型就是类的类型,就是描述一个类是什么,有那些属性和方法。所以我们可以通过类的类型,来获取一个类属性和方法,并且调用它的属性和方法,这就是反射的基础。

举个简单的例子

Person类

package cn.zhuangxp.reflect;

/**
 * @author BEAN_BAG
 * @date 2018年4月29日
 * @description Person实体类
 */
public class Person {
    private String name;
    private int age;
    private String hobby;
    public String msg = "HelloWorld";
    public String phone = "13066612345";
    private String email = "[email protected]";

    public Person() {
    }

    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }

    private Person(String name, int age, String hobby) {
        this.name = name;
        this.age = age;
        this.hobby = hobby;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name=‘" + name + ‘‘‘ +
                ", age=" + age +
                ", hobby=‘" + hobby + ‘‘‘ +
                ‘}‘;
    }

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

    private void play(String hobby) {
        System.out.println("我的爱好是:" + hobby);
    }

}

测试类

public class Demo01 {
    public static void main(String[] args) throws ClassNotFoundException {
        //这说明任何一个类都有一个隐含的静态成员变量class,这种方式是通过获取类的静态成员变量class得到的
        Class clazz1 = Person.class;
        System.out.println(clazz1.getName());

        //这种方式是通过一个类的对象的getClass()方法获得的
        Person p = new Person();
        Class<? extends Person> clazz2 = p.getClass();
        System.out.println(clazz2.getName());

        //这种方法是Class类调用forName方法,通过一个类的全量限定名获得
        Class<?> clazz3 = Class.forName("cn.zhuangxp.reflect.Person");
        System.out.println(clazz3.getName());

    }
}

结果

cn.zhuangxp.reflect.Person
cn.zhuangxp.reflect.Person
cn.zhuangxp.reflect.Person

4、Java反射的相关操作

获取指定成员方法Method

public class Demo02 {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("cn.zhuangxp.reflect.Person");
        Object instance = clazz.newInstance();

        /**
         * 返回某个类的指定的公共(public)成员方法
         */
        Method method1 = clazz.getMethod("say",String.class,int.class);
        method1.invoke(instance,"BEAN_BAG",23);

        /**
         * 返回某个类的指定已声明方法
         */
        Method method2 = clazz.getDeclaredMethod("play", String.class);
        //取消Java权限控制检查
        method2.setAccessible(true);
        method2.invoke(instance,"乒乓球");

    }
}

结果

我叫:BEAN_BAG,今年:23
我的爱好是:乒乓球

获取所有方法

public class Demo03 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class<?> clazz = Class.forName("cn.zhuangxp.reflect.Person");
        /**
         * 返回某个类的所有公共(public)方法,,包括其继承类的公共方法,
         * 也包括它所实现的接口的方法。
         */
        Method[] methods = clazz.getMethods();
        for (Method m : methods) {
            System.out.println(m.getName());
        }
        System.out.println("=================================================");

        /**
         * 返回某个类的所有方法,包括公共、保护、默认访问和私有的方法。
         * 但是不包括继承的方法,当然也包括它所实现的接口的方法。
         */
        Method[] methods1 = clazz.getDeclaredMethods();
        for (Method m : methods1){
            System.out.println(m.getName());
        }

    }
}

结果

toString
getName
setName
setMsg
say
setHobby
getMsg
setAge
getHobby
getAge
wait
wait
wait
equals
hashCode
getClass
notify
notifyAll
=================================================
toString
getName
setName
play
setMsg
say
setHobby
getMsg
setAge
getHobby
getAge

获取成员变量Field

public class Demo04 {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("cn.zhuangxp.reflect.Person");
        Object instance = clazz.newInstance();
        /**
         * 获得该类中指定的public成员变量,包括其父类变量
         */
        Field field = clazz.getField("msg");
        Object msg = field.get(instance);
        System.out.println(msg.toString());

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

        /**
         * 获得该类中所有的自身声明的变量,不包括其父类的变量
         */
        Field field1 = clazz.getDeclaredField("email");
        field1.setAccessible(true);
        Object email = field1.get(instance);
        System.out.println(email.toString());
    }
}

结果

HelloWorld
===============================================
[email protected]163.com

获取所有的成员变量

public class Demo05 {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("cn.zhuangxp.reflect.Person");
        Object instance = clazz.newInstance();
        /**
         * 获得该类所有的public成员变量,包括其父类变量
         */
        Field[] fields = clazz.getFields();
        for (Field f : fields){
            Object o = f.get(instance);
            System.out.println(o.toString());
        }
        System.out.println("===========================================");
        /**
         * 获得该类自身声明的所有变量,不包括其父类的变量
         */
        Field[] fields1 = clazz.getDeclaredFields();
        for (Field f : fields1){
            System.out.println(f.getName());
        }
    }
}

结果

HelloWorld
13066612345
===========================================
name
age
hobby
msg
phone
email

获取构造器

public class Demo06 {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("cn.zhuangxp.reflect.Person");
        Object instance = clazz.newInstance();

        /**
         * 获得该类的public构造器
         */
        Constructor<?> constructor = clazz.getConstructor(String.class,int.class);
        Object o = constructor.newInstance("BEAN_BAG", 23);
        System.out.println(o);
        System.out.println("=========================================");
        /**
         * 获得该类所有的构造器
         */
        Constructor<?> constructor1 = clazz.getDeclaredConstructor(String.class,int.class,String.class);
        constructor1.setAccessible(true);
        Object o1 = constructor1.newInstance("mm",22,"English");
        System.out.println(o1);
    }
}

结果

Person{name=‘BEAN_BAG‘, age=23, hobby=‘null‘}
=========================================
Person{name=‘mm‘, age=22, hobby=‘English‘}

获取所有的构造器

public class Demo07 {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("cn.zhuangxp.reflect.Person");
        Object instance = clazz.newInstance();
        /**
         * 获得该类所有的public构造器
         */
        Constructor<?>[] constructors = clazz.getConstructors();
        for (Constructor c : constructors){
            System.out.println(c.getName());
        }
        System.out.println("====================================");
        /**
         * 获得该类所有的构造器
         */
        Constructor<?>[] constructors1 = clazz.getDeclaredConstructors();
        for (Constructor c : constructors1){
            System.out.println(c.getName());
        }

    }
}

结果

cn.zhuangxp.reflect.Person
cn.zhuangxp.reflect.Person
====================================
cn.zhuangxp.reflect.Person
cn.zhuangxp.reflect.Person
cn.zhuangxp.reflect.Person

5、通过反射了解泛型的本质

Java中集合的泛型,是防止错误输入的,只在编译阶段有效。如果绕过编译期,到运行期就无效了。所以,我们可以通过Java的反射绕过泛型检查,完整代码如下:

public class Demo08 {
    public static void main(String[] args) throws Exception {
        List<String> list = new ArrayList<String>();
        list.add("zhuang14");//允许添加
        //list.add(25);//添加int类型报错,因为泛型为String
        //获取list的类类型
        Class<? extends List> clazz = list.getClass();
        //获取list集合的add方法
        Method addMethod = clazz.getMethod("add", Object.class);
        addMethod.invoke(list,25);
        //结果
        System.out.println(list);//[zhuang14, 25]

    }
}

 


以上是关于Java中的反射的主要内容,如果未能解决你的问题,请参考以下文章

反射机制入门

反射机制入门

反射机制入门

对于java反射的理解

java Java中的缓存反射访问(来自Spring Framework代码库)

LockSupport.java 中的 FIFO 互斥代码片段