Java反射与joor反射库的使用

java原生反射的使用

反射构造对象

  //获得指定对象的构造方法,参数值传入与构造方法参数对应的类型
  Constructor  constructor = peopleClass.getConstructor(String.class);

  //分为无参和有参,参数传入与构造方法参数对应的值,获得对象引用
  People people = (People) constructor.newInstance("Devin");

反射方法

函数 作用 备注
getDeclaredMethod 获取指定的 private、protected、default、public 的函数 只能取到的该类自身中定义的函数,从父类中继承的函数不能够获取到。
getDeclaredMethods 获取全部的 private、protected、default、public 的函数 只能取到的该类自身中定义的函数,从父类中继承的函数不能够获取到。
getMethod 获取指定的 public 函数 父类中的公有函数也能够获取到
getMethods 获取全部的 public 函数 父类中的公有函数也能够获取到
setAccessible() 设置该方法是否可被访问 设置true表示可以访问该方法
invoke() 调用该方法,第一个参数表示该方法所在类的对象,第二个参数传入该方法所需的参数值 如果是静态函数,第一个参数传入null.如果该方法有返回值,则返回方法执行后的返回值,如果没有,则返回null
People people = new People("lisi");
Class<? extends People> peopleClass = people.getClass();
 Method setAgeMethod = peopleClass.getDeclaredMethod("setAge", int.class);
//设置true表示可以访问该方法 
setAgeMethod.setAccessible(true);
//调用此方法,如果方法有返回值,则返回方法执行后的返回值,如果没有,则返回 null
Object obj=setAgeMethod.invoke(people, 20);

反射字段

函数 作用 备注
getDeclaredField 获取指定的 private、protected、default、public 的字段 只能取到的该类自身中定义的字段,从父类中继承的字段不能够获取到。
getDeclaredFields 获取全部的 private、protected、default、public 的字段 只能取到的该类自身中定义的字段,从父类中继承的字段不能够获取到。
getField 获取指定的 public 字段 父类中的公有字段也能够获取到
getFields 获取全部的 public 字段 父类中的公有字段也能够获取到
setAccessible() 设置该字段是否可被访问 设置true表示可以访问该字段
set()/setInt()/... 修改字段的值 第一个参数为字段所在的类的对象,第二个参数为要修改的值 (final 字段是不可修改的)
get()/getInt()/... 获取字段的值 第一个参数为属性所在的类的对象,表示获取该类的该属性。若为null,则获取的是静态属性。

示例一: 

People people = new People("lisi");
Class<? extends People> peopleClass = people.getClass();
Field nameField = peopleClass.getDeclaredField("name");
nameField.setAccessible(true);
String name = (String) nameField.get(people);

示例二 :


package myJavaproject;
 
/**
*代码来源:Java核心技术 卷I
*Java中利用反射打印一个类的所有信息
*只为分享给他人,而将代码奉上
*/
import java.util.*;
import java.lang.reflect.*;
 
public class ReflectionTest {
 
	public static void main(String[] args) {
 
		String name = "";
		if(args.length>0)
			name = args[0];
		else {
			Scanner in  = new Scanner(System.in);
			System.out.println("Enter class name (e.g.java.Date):");
			name = in.next();
		}
		try {
            //获取类对象
			Class cl = Class.forName(name);
			Class supercl = cl.getSuperclass();
            //获取类的修饰符
			String modifiers = Modifier.toString(cl.getModifiers());
			if(modifiers.length()>0) {
				System.out.print(modifiers+" ");
			}
			System.out.print("class "+name);
			if(supercl != null && supercl!=Object.class) {
				System.out.print(" extends "+supercl.getName());
			}
			System.out.print("\n{\n");
            //打印类的构造函数
			printConstructors(cl);
			System.out.println();
            //打印类的方法
			printMethods(cl);
			System.out.println();
            //打印类的域
			printFields(cl);
			System.out.println("}");
		}catch(ClassNotFoundException e) {
			e.printStackTrace();
		}
		System.exit(0);
	}
 
	//打印类的构造函数
	public static void printConstructors(Class cl) {
 
        //获得所有的构造函数并存放在数组中
		Constructor[] constructors = cl.getDeclaredConstructors();
        //获得函数修饰符和所需要的域并打印
		for(Constructor c:constructors) {
			String name = c.getName();
			System.out.print("    ");
			String modifiers = Modifier.toString(c.getModifiers());
			if(modifiers.length()>0) {
				System.out.print(modifiers+" ");
			}
			System.out.print(name+"(");
			Class[] paramTypes = c.getParameterTypes();
			for(int j=0;j<paramTypes.length;j++) {
				if(j>0) {
					System.out.print(", ");
					System.out.print(paramTypes[j].getName());
				}
			}
			System.out.println(");");
		}	
	}
	
    //打印类的方法
	public static void printMethods(Class cl) {
		Method[] methods = cl.getDeclaredMethods();
		for(Method m:methods) {
            //获取返回值类型并自动装包
			Class retType = m.getReturnType();
			String name = m.getName();
			System.out.print("    ");
			String modifiers = Modifier.toString(m.getModifiers());
			if(modifiers.length()>0) {
				System.out.print(modifiers+" ");
			}
			System.out.print(retType.getName()+" "+name+"(");
			Class[] paramTypes = m.getParameterTypes();
			for(int j = 0;j<paramTypes.length;j++) {
				if(j>0) {
					System.out.print(", ");
					
				}
				System.out.print(paramTypes[j].getName());
			}
			System.out.println(");");
		}	
	}
 
    //打印类的域
	public static void printFields(Class cl) {
		Field[] fields = cl.getDeclaredFields();
		for(Field f:fields) {
            //获取域的类型并自动装包
			Class type = f.getType();
			String name = f.getName();
			System.out.print("    ");
			String modifiers = Modifier.toString(f.getModifiers());
			if(modifiers.length()>0) {
				System.out.print(modifiers+" ");
				
			}
			System.out.println(type.getName()+" "+name+";");
		}
	}

 

 


joor反射库的使用

github:
https://github.com/jOOQ/jOOR
中文 README:
https://github.com/tianzhijiexian/Android-Best-Practices/blob/master/2015.9/reflect/README%20-%20chinese.md

概要

jOOR - Fluent Reflection in Java jOOR is a very simple fluent API that gives access to your Java Class structures in a more intuitive way. The JDK’s reflection APIs are hard and verbose to use. Other languages have much simpler constructs to access type meta information at runtime. Let us make Java reflection better. http://www.jooq.org/products

jOOR是基于java反射api的一个简单包装类,简单却十分实用。

jOOR这个名字是从jOOQ中得到的灵感,jOOQ是一个很棒的SQL的API。

gradle配置

compile'org.jooq:joor:0.9.6'

基于的库

完全不用!

jOOR功能介绍

1、提供on()操作符对类名、Class、Object进行统一实例化为Reflect对象,后续所有的反射操作基于该Reflect对象。 
2、有功能调用方式均被封装成返回Reflect对象的链式结构,在使用上使得代码更加简洁。 
3、对方法的签名匹配封装了更完善的匹配规则,包括精确匹配exactMethod()、近似匹配similarMethod()【对函数参数的近似匹配(int -> Integer)】和基类搜索等。 
4、调用私有方法的不需要显示调用setAccessible(),内部动态读取public标记自动适配。 
5、更加简洁的实现了对象构造函数的反射调用create()方法。 
6、函数的调用call()方法组合成了可以拼接在Reflect的对象后面的链式方法。 
7、额外增加了高级操作符as(),它实现了类的代理访问以及POJO对象的get/set/is方法实现。

API方法介绍
 

/**  
* https://github.com/jOOQ/jOOR   
* Reflect实际是对原生java reflect进行封装,屏蔽了无关细节。  
*   
* Reflect.create 用来调用之前的类的构造方法,有两种重载,一种有参数,一种无参数  
* Reflect.call 方法调用,传入方法名和参数,如有返回值还需要调用get  
* Reflect.get 获取(field和method返回)值相关,会进行类型转换,常与call和field组合使用  
* Reflect.field 获取属性值相关,需要调用get获取该值  
* Reflect.set 设置属性相关。  
*/  


//1、通过类名转换成一个Reflect对象:
public static Reflect on(String name);
public static Reflect on(String name, ClassLoader classLoader);
public static Reflect on(Class<?> clazz);

//2、将一个类对象转换成一个Reflect对象:
public static Reflect on(Object object);

//3、修改一个AccessibleObject类型的对象的访问权限:
public static <T extends AccessibleObject> T accessible(T accessible);

//4、返回Reflect对象具体包装的类型,类型为Class或者对象,由操作符on()的重载参数决定:
public <T> T get();

//5、将name指定的field转换成一个Reflect对象,后续对field的操作变为对Reflect对象的操作:
public Reflect field(String name);

//6、返回当前Reflect对象的所有field属性,并转换成Reflect对象的map:
public Map<String, Reflect> fields();

//7、修改(获取)field属性值:
public Reflect set(String name, Object value);
public <T> T get(String name);

//8、反射调用name指定的函数,此函数封装了对函数的签名的精准匹配和近似匹配:
public Reflect call(String name);
public Reflect call(String name, Object... args);

//9、反射调用指定类的构造函数,也封装了精准匹配和近似匹配:
public Reflect create();
public Reflect create(Object... args);

//10、返回当前Reflect对象封装的对象类型:
public Class<?> type();

//11、给封装对象创建一个代理访问,还实现了对POJO对象的setXX/getXX/isxx功能(此为Reflect对象的高级功能):
public <P> P as(Class<P> proxyType);

一个简单的示例

// All examples assume the following static import:
import static org.joor.Reflect.*;

String world = on("java.lang.String")  // on后面放入类的全名,这里是String类
                .create("Hello World") // 将字符串“Hello World”,传入构造方法中
                .call("substring", 6)  // 执行subString这个方法,并且传入6作为参数
                .call("toString")      // 执行toString方法
                .get();                // 得到包装好的类,这里是一个String对象

更多示例

建立一个测试类:

package kale.androidframework;

public class Kale {

    private String name;

    private String className;

    Kale() {

    }

    Kale(String clsName) {
        this.className = clsName;
    }

    public void setName(String name) {
        this.name = name;
    }

    private String getName() {
        return name;
    }

    public String getClassName() {
        return className;
    }

    public static void method() {
        
    }
}

这个类中有有参构造方法和无参构造方法,还有get和set方法。这里的类变量都是private的,有一个get方法也是private的。我们现在要尝试利用jOOR来访问变量和方法:

String name = null;
Kale kale;
// 【创建类】
kale = Reflect.on(Kale.class).create().get(); // 无参数 
kale = Reflect.on(Kale.class).create("kale class name").get();// 有参数
System.err.println("------------------> class name = " + kale.getClassName());

// 【调用方法】
Reflect.on(kale).call("setName","调用setName");// 多参数
System.err.println("调用方法:name = " + Reflect.on(kale).call("getName"));// 无参数
        
// 【得到变量】
name = Reflect.on(kale).field("name").get();// 复杂
name = Reflect.on(kale).get("name");// 简单
System.err.println("得到变量值: name = " + name);
        
// 【设置变量的值】
Reflect.on(kale).set("className", "hello");
System.err.println("设置变量的值: name = " + kale.getClassName());
System.err.println("设置变量的值: name = " + Reflect.on(kale).set("className", "hello2").get("className"));  

典型用法

method调用:

//Instance methods on的参数是一个对象
//Static methods on的参数是一个类

// Instance methods
//value0 = "12";
final String value0 = Reflect.on((Object) "1234").call("substring", 0, 2).get();


// Static methods
//value1 = "true";
final String value1 = Reflect.on(String.class).call("valueOf", true).get(); 

Field属性get/set操作:

public static class TestField {
    private static final int SF_INT1 = new Integer(0);
    private static final Integer SF_INT2 = new Integer(0);

    private final int F_INT1 = new Integer(0);
    private final Integer F_INT2 = new Integer(0);

    private TestField I_DATA;
}

//Instant fields,on的参数是一个对象
//Static fields,on的参数是一个类

// Instance fields
// ----------------


TestField testField = new TestField();

/**
 * 修改final属性
 */
final Integer value0 = Reflect.on(testField).set("F_INT2", 1).get("F_INT2"); //value0 = 1;

/**
 * 获取属性值
 */
final int value1 = Reflect.on(testField).field("F_INT2").get(); //value1 = 1;

/**
 * 链式修改多个属性值
 */
Reflect.on(testField).set("F_INT1", 2).set("F_INT2", 2);


/**
 * 复杂链式修改多个属性值
 */
Reflect.on(testField).set("I_DATA", Reflect.on(TestField.class).create())
    .field("I_DATA").set("F_INT1", 3).set("F_INT2", 3);


// Static fields
// ----------------


/**
 * 修改static final属性
 */
final int value2 = Reflect.on(TestField.class).set("SF_INT1", 4).get("SF_INT1"); //value2 = 4;

/**
 * 获取静态属性值
 */
final int value3 = Reflect.on(TestField.class).field("SF_INT1").get(); //value3 = 4;

抽象代理

jOOR也可以方便的使用java.lang.reflect.Proxy的API

public interface StringProxy {
  String substring(int beginIndex);
}

String substring = on("java.lang.String")
                    .create("Hello World")
                    .as(StringProxy.class) // 为包装类建立一个代理
                    .substring(6);         // 访问代理方法

代理调用、POJO对象支持

/**
 * 代理调用String
 */
final String value0 = Reflect.on((Object) "abc").as(Test6.class).substring(1, 2); //value0 = "b";

/**
 * POJO对象的map代理
 */
class MyMap extends HashMap<String, Object> {
    String baz;
    public void setBaz(String baz) {
    this.baz = "MyMap: " + baz;
    }

    public String getBaz() {
    return baz;
    }
}


Map<String, Object> map = new MyMap();

Reflect.on(map).as(Test6.class).setFoo("abc");
int size = map.size(); //size = 1;
final String value1 = (String) map.get("foo"); //value1 = "abc";
final String value2 = Reflect.on(map).as(Test6.class).getFoo(); //value2 = "abc";

Reflect.on(map).as(Test6.class).setBar(true);
size = map.size(); //size = 2;
final boolean value3 = Reflect.on(map).as(Test6.class).isBar(); //value3 = true;

Reflect.on(map).as(Test6.class).setBaz("baz-test");
size = map.size(); //size = 2;
final String value4 = (String) map.get("baz"); //value4 = null;
final String value5 = Reflect.on(map).as(Test6.class).getBaz(); //value5 = "MyMap: baz-test";

Reflect.on(map).as(Test6.class).testIgnore(); //crash

public interface Test6 {

    void setFoo(String s);

    void setBar(boolean b);

    void setBaz(String baz);

    void testIgnore();

    String getFoo();

    boolean isBar();

    String getBaz();

    String substring(int beginIndex, int endIndex);

}

和java.lang.reflect的对比

1.Instant Method

使用jOOR的代码:

Employee[] employees = on(department).call("getEmployees").get();

for (Employee employee : employees) {
  Street street = on(employee).call("getAddress").call("getStreet").get();
  System.out.println(street);
}

用传统的反射方式写的代码:

try {
  Method getEmployeesMethod = department.getClass().getMethod("getEmployees");
  Employee employees = (Employee[]) getEmployeesMethod.invoke(department);

  for (Employee employee : employees) {
    Method getAddressMethod = employee.getClass().getMethod("getAddress");
    Address address = (Address) getAddressMethod.invoke(employee);

    Method getStreetMethod = address.getClass().getMethod("getStreet");
    Street street = (Street) getStreetMethod.invoke(address);

    System.out.println(street);
  }
}

// There are many checked exceptions that you are likely to ignore anyway 
catch (Exception ignore) {

  // ... or maybe just wrap in your preferred runtime exception:
  throw new RuntimeException(e);
}

2.Static Method

使用JOOR的代码:

    /**
     * 反射读取系统SystemProperties的属性值
     * @param key
     * @param defaultValue
     * @return
     */
    public static String getValueEx(String key, String defaultValue) {
        String value;
        try {
            value = Reflect.on("android.os.SystemProperties")
                .call("get", key, defaultValue).get();
        } catch (ReflectException e) {
            e.printStackTrace();
            value = "";
        }
        return value;
    }

 JDK的反射API:

    /**
     * 反射读取系统SystemProperties的属性值
     * @param key
     * @param defaultValue
     * @return
     */
    public static String getValue(String key, String defaultValue) {
        String value = "";
        try {
            Class<?> cls = Class.forName("android.os.SystemProperties");
            Method getMethod = cls.getDeclaredMethod("get", String.class, String.class);
            getMethod.setAccessible(true);
            return (String) getMethod.invoke(null, key, defaultValue);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return value;
    }

从上面的例子就可以看到jOOR明显的优势:

1、简化了反射冗长的异常处理。 
2、简化了对Class、Method、Field、Constructor反射类的实例化,改为统一Reflect替换。 
3、支持private方法的调用,内部动态区分是否需要accessible()。 
4、将反射调用封装为更流行的链式调用方式,代码更容易理解(类似Rxjava的封装方式)。 
5、支持类型内部wrap转换(泛型实现)。

总结

在项目中需要较多地方使用反射时,可以采用jOOR的封装来简化反射的调用;后续需要进行反射优化时(比如对Class、Method、Field仅在首次调用时获取并缓存起来,后续仅仅调用缓存的invoke()),jOOR的统一封装对优化也提供了便利。

参考:

1.https://www.jianshu.com/p/5a955285dfc5

2.https://blog.csdn.net/bibingyan/article/details/56481801 

展开阅读全文

没有更多推荐了,返回首页