java的反射机制和实例应用
阅读(273)
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