java的反射机制和实例应用
阅读(298)
2018-01-05
有时候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/article/50.html
