前言
上一篇介绍了依赖注入中的注解,而且篇末还贴了一段通过反射操作注解的代码,传送门https://www.jianshu.com/p/9d20a7391057
一.反射概念
在运行状态中,能够获取到任意一个类的属性和方法,并且能够操作对应的属性和方法,我们把这种能动态操作对象属性和方法的方式称为Java反射机制。反射就是把java类中的每个成员映射成一个个的对象,我们就是要取出这些对象进行操作。
要获取一个类的属性和方法,就得获取他的字节码class文件(.java文件编译后都会对应有一个.class文件)对应Class类型的对象,Class对象的由来就是将字节码class文件加载进内存并创建一个Class的对象。
二.Class类
1.Class类简介
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。也就是jvm中每个类都有对应的Class对象。
Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass方法自动构造的。
2.Class对象获取
三种方式获取:
1.该类对象.getClass();
2.该类(或数据类型).class;
3.利用Class.forName(包名+类名),参数为该类的完整路径;
最好用第三种,前两种方式依赖太强。
package com.dzy.samefunctiondemo.fanshe;
public class Programmer {
}
public class Reflect {
public static void main(String[] args) {
Programmer programmer = new Programmer();
Class proClass1 = programmer.getClass();
Class proClass2 = Programmer.class;
try {
Class proClass3 = Class.forName("com.dzy.samefunctiondemo.fanshe.Programmer");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
三.反射使用
1.获取构造方法
package com.dzy.samefunctiondemo.fanshe;
public class Programmer {
public Programmer(){
}
public Programmer(String name){
System.out.println("Name:"+name);
}
private Programmer(int age){
System.out.println("Age:"+age);
}
protected Programmer(double weight){
}
}
public class Reflect {
public static void main(String[] args) {
try {
Class proClass = Class.forName("com.dzy.samefunctiondemo.fanshe.Programmer");
//获取所有构造方法
Constructor[] constructors1 = proClass.getDeclaredConstructors();
//获取所有公共(public)构造方法
Constructor[] constructors2 = proClass.getConstructors();
//获取某个带参数的构造方法
Constructor constructor1 = proClass.getDeclaredConstructor(int.class);
constructor1.setAccessible(true);//由于私有方法无访问权限,这个是直接开启访问权限
constructor1.newInstance(50);//创建对应构造器的对象
//获取某个带参数的公共构造方法
Constructor constructor2 = proClass.getConstructor(String.class);
constructor2.newInstance("heweii");//创建对应构造器的对象
} catch (Exception e) {
e.printStackTrace();
}
}
}
打印结果,确实是ok的
Age:50
Name:heweii
2.获取普通方法
在Programmer中创建以下方法
public void method1(){
System.out.println("method1:");
}
public void method2(String str){
System.out.println("method2:"+str);
}
private void method3(int num){
System.out.println("method3:"+num);
}
protected void method4(double dou){
System.out.println("method4:"+dou);
}
要注意的是,在调用方法的时候需要该类的实例,这个也好理解,访问类的非静态方法必须通过该类的对象访问
proClass.getDeclaredMethods();//所有方法
proClass.getMethods();//公共方法
//获取带参的方法
Method method1 = proClass.getDeclaredMethod("method4",double.class);
Object o = proClass.getConstructor().newInstance();//默认构造方法
method1.setAccessible(true);//非公共方法必须要
method1.invoke(o,18.88);
完全ok
method4:18.88
3.获取成员变量
在Programmer中新增以下字段
public String name;
private int age;
protected double weight;
proClass.getDeclaredFields();//所有字段
proClass.getFields();//公共字段
//获取公共的成员变量
Field field = proClass.getField("name");
Object obj = proClass.getConstructor().newInstance();//默认构造方法
field.set(obj , "hawaii");//赋值
System.out.println("Field---Name:"+((Programmer)obj).name);
Field---Name:hawaii
再回头看上一篇的利用反射实现依赖注入的代码,是不是就看起来很简单了
public static void bindView(final Activity activity){
Class<Activity> activityClass = (Class<Activity>) activity.getClass();
Field[] fields = activityClass.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(BindView.class)){
int id = field.getAnnotation(BindView.class).value();
View view = activity.findViewById(id);
field.setAccessible(true);
try {
field.set(activity , view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
Method[] methods = activityClass.getDeclaredMethods();
for (final Method method : methods) {
OnClick onClick = method.getAnnotation(OnClick.class);
if (onClick != null) {
int[] ids = onClick.value();
for (int id : ids) {
activity.findViewById(id).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
method.setAccessible(true);
try {
method.invoke(activity);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
});
}
}
}
}
参考在线JavaApi链接
http://tool.oschina.net/apidocs/apidoc?api=jdk_7u4
网友评论