1.通过反射,我们可以构建实例,得到成员变量的值,得到方法并调用。
还可以获得定义在成员变量、方法、方法参数上的注解。
接下来看代码实现,然后讲原理。
1)构建无参实例:通过反射调用无参构造函数
//1.通过全类名加载字节码对象 class clazz = class.forname("com.example.lib.person"); //2.通过类的字节码拿到定义的构造函数 constructor constructor = clazz.getconstructor(); //3.通过构造方法创建对象 object obj = constructor.newinstance();
2)构建有参数实例:
//1.通过全类名加载字节码对象 class clazz = class.forname("com.example.lib.person"); //2.通过类的字节码拿到定义的构造函数 constructor constructor = clazz.getconstructor(int.class,string.class); //3.通过构造方法创建对象 object obj = constructor.newinstance(20,"xiaohua");
3)通过反射获取成员变量的值。
//4.通过属性名获取属性 field field = clazz.getdeclaredfield("age"); field.setaccessible(true); //5.调用get方法拿到对象obj属性age的值 integer age = (integer) field.get(obj);
4)通过反射调用对象的方法。
//4.通过方法名和参数类型,拿到方法 method = clazz.getmethod("setage", int.class); //5.调用方法 obj是哪个对象身上的方法。 method.invoke(obj, 21); method = clazz.getmethod("getage"); method.invoke(obj);
5).通过反射获取静态变量的值。
//1.通过全类名加载字节码对象 class clazz = class.forname("com.example.lib.person"); //2.获取静态属性id field field = clazz.getfield("id"); field.setaccessible(true); //3.拿到静态属性id的值。 // 因为静态变量存在方法区,在对象创建之前,就已经加装到了内存 //所以,没有对象,也可以获取变量的值,这里传null也是可以的。 int id = (int) field.get(null);
2.通过反射获取定义的注解的值
1)获取成员变量的注解以及值。
@target({elementtype.field})@retention(retentionpolicy.runtime)public @interface bindview { int value();}
public class mainactivity { @bindview(10000) textview textview;}
//10通过反射拿到定义在属性上的注解 class clazz = mainactivity.class; field textview = clazz.getdeclaredfield("textview"); bindview bindview = textview.getannotation(bindview.class); int txtid = bindview.value();
3)通过反射获取定义在方法和方法参数上的注解以及值
@target(elementtype.method)@retention(retentionpolicy.runtime)public @interface post { string value() default "";}
public interface networkinterface { @post("http://www.baidu.com") call getperson(@queue("name") string name, @queue("200") int price);}
//11通过反射拿到方法上定义的注解 clazz = networkinterface.class; method method = clazz.getmethod("getperson", string.class, int.class); //获取post注解 post post = method.getannotation(post.class); //获取值 string url = post.value();
//12通过反射拿到参数上的注解 //为是个二维数组,因为方法参数会有多个,一个参数有可能定义多个注解 annotation[][] annotations = method.getparameterannotations(); for (annotation[] ans : annotations) { for (annotation an : ans) { if (an instanceof queue) { queue queue = (queue) an; string value = queue.value(); } } }
4)获取方法的参数和返回值类型。
//13.拿到方法参数的类型。 type[] types = method.getgenericparametertypes(); for (type type : types) { system.out.println(type.tostring()); } //14.获取方法返回值类型 type type = method.getgenericreturntype();
3总结:通过反射,可以拿到对象身上的成员变量的值、调用方法,获取定义在成员变量、方法和 方法参数上的注解。retrofit 就用到了注解加反射技术,和动态代理(这个技术稍后分享)
4.通过反射,可以做到以上事情。反射的原理是啥?
1)我们写的源代码是.java文件,通过javac编译后成为.class文件,即字节码文件。
2)程序执行时,jvm会类加载字节码文件到内存,严格意义上说是加载到方法区,并转换成
java.lang.class对象。万事万物皆对象,class被称为类对象,描述类在元数据空间的数据结构,包含类中定义的属性、方法、构造方法、注解、接口等信息。
所有反射的第一步是拿到类对象class对象。拿到了class对象,也就拿到了类中定义的一切。
class clazz = class.forname(com.example.lib.person);
这行代码就是通过类加载器把person类加载到内存,并得到对应的class 对象。
以上就是java反射机制的原理和实现方法是什么?的详细内容。