java的反射机制和实例应用

标签: 反射
2018-01-05 阅读(101)

有时候bean转map,动态加载插件,通过后台配置动态调用某接口方法等等。都需要用到java的反射机制。下面简单介绍下java的反射机制。


反射创建和new的很重要区别在于,new后面必须跟一个具体的类型,而在编译的时候JVM就会去检查new后面的类是否存在,如果存在则编译通不过,而反射则不会,反射的类装载在编译的时候JVM是不会检查的,这样的好处是可以实现的动态切换,也就是运行的时候才才决定用哪个类。


反射机制

User.java类,用于反射演示

package com.weizhixi.reflect;

/**
 * Created by cxq on 2018-01-04.
 */
public class User {
    public final static String HELLO = "HELLO";

    private Integer id;
    private String name;

    //实例化块,该块在实例被创建之后执行
    {
        System.out.println("实例化块被执行了,说明实例被创建了!");
    }

    //静态块,静态块会在类被加载后执行
    static{
        System.out.println("静态块被执行了,说明类被创建了!");
    }

    public void say(){
        System.out.println("say:hello");
    }

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}


Test.java

package com.weizhixi.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * Created by cxq on 2018-01-04.
 */
public class Test{
    public static void main(String[] args) throws Exception{
        //类加载,类加载并不是实例的创建
        Class cls = Class.forName("com.weizhixi.reflect.User");//class表示该类的引用,这时候,静态块被执行了,说明类被创建了!
        //类实例的创建,记住,只有返回类型是Object类型的时候我们才
        //需要进行类型强转
        User user = (User)cls.newInstance(); //instance实例,这时候,实例化块被执行了,说明实例被创建了!
        user.say();
        //say:hello

        //获得类的所有属性,包括私有的
        Field[] fields = cls.getDeclaredFields();//field属性
        for(int i=0;i<fields.length;i++){
            Field f = fields[i];
            //modifier修饰符
            System.out.println("属性:"+f.getName()+",的修饰符是:"+f.getModifiers());
        }
        //属性:HELLO,的修饰符是:25
        //属性:id,的修饰符是:2
        //属性:name,的修饰符是:2


        //返回所有Method对象的数组
        Method[] cc = cls.getDeclaredMethods();
        for(int i=0;i<cc.length;i++){
            Method m = cc[i];
            System.out.println("修饰符:"+m.getModifiers()+",返回类型:"+m.getReturnType()+",名称"+m.getName());
        }
        //修饰符:1,返回类型:void,名称say
        //修饰符:1,返回类型:void,名称setId
        //修饰符:1,返回类型:class java.lang.String,名称getName
        //修饰符:1,返回类型:class java.lang.Integer,名称getId
        //修饰符:1,返回类型:void,名称setName

    }
    
}

反射getModifiers对应修饰符

public class Modifier {
    public static final int PUBLIC = 1;
    public static final int PRIVATE = 2;
    public static final int PROTECTED = 4;
    public static final int STATIC = 8;
    public static final int FINAL = 16;
    public static final int SYNCHRONIZED = 32;
    public static final int VOLATILE = 64;
    public static final int TRANSIENT = 128;
    public static final int NATIVE = 256;
    public static final int INTERFACE = 512;
    public static final int ABSTRACT = 1024;
    public static final int STRICT = 2048;
    ...
}

反射后调用相应方法

public static void test() throws Exception{
    //加载类
    Class cls = Class.forName("com.weizhixi.reflect.User");
    //创建实体
    Object user = cls.newInstance();

    //调用User实体say方法
    Method say = cls.getDeclaredMethod("say");
    say.invoke(user);
    //say:hello

    //调用User实体setName方法,并传入参数
    Method setName = cls.getDeclaredMethod("setName",String.class);
    setName.invoke(user, "world");

    //调用User实体getName方法,获取上步设置的值
    Method getName = cls.getDeclaredMethod("getName");
    System.out.println(getName.invoke(user));
    //world

}

支持多参数,看源码:

@CallerSensitive
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
    throws NoSuchMethodException, SecurityException {
    // be very careful not to change the stack depth of this
    // checkMemberAccess call for security reasons
    // see java.lang.SecurityManager.checkMemberAccess
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
    Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
    if (method == null) {
        throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
    }
    return method;
}

Class<?>...多参数,如getDeclaredMethod("setName", String.class, String.class, String.class)



实例应用

动态切换调用的类

场景如:统一方法say()。在动态载入猫的时候,猫说猫话;再动态切换成狗的时候,狗说够话。


新建Action.java,动作接口。接口中有say()方法。

package com.weizhixi.reflect;

public interface Action {

    public void say();

}


新建猫类Cat.java,实现Action接口。

package com.weizhixi.reflect;

public class Cat implements Action {
    @Override
    public void say() {
        System.out.print("Cat say:mao~mao~");
    }
}


再新建狗类Dog.java,实现Action接口。

package com.weizhixi.reflect;

public class Dog implements Action {
    @Override
    public void say() {
        System.out.print("Dog say:wang~wang~");
    }
}


新建测试演示类Test.java

package com.weizhixi.reflect;

/**
 * Created by cxq on 2018-01-04.
 */
public class Test1 {

    public static void main(String[] args) throws Exception{
        //假如我们把,实现的类,放入数据库。
        //动态获取类名,来实现调用统一方法say()
        //啊猫,啊狗,自己说自己的话。
        
        //action("com.weizhixi.reflect.Dog");
        //Dog say:wang~wang~
        
        action("com.weizhixi.reflect.Cat");
        //Cat say:mao~mao~
    }

    // 动态传入实现的class类名,如Cat/Dog
    public static void action(String clazz) throws Exception{
        Class cls = Class.forName(clazz);
        Action act = (Action)cls.newInstance();
        act.say();
    }

}


这个模拟可以用于但不限于,如:背景动态场景切换,动态主题切换,动态加载模块,动态加载插件等等。



原创文章,转载请注明出处:https://www.weizhixi.com/user/index/article/id/50.html

分类:
点击(153) 阅读(101) 举报