Java高级特性——反射
定义
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制
用途
在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法。当然,也不是所有的都适合反射,之前就遇到一个案例,通过反射得到的结果与预期不符。阅读源码发现,经过层层调用后在最终返回结果的地方对应用的权限进行了校验,对于没有权限的应用返回值是没有意义的缺省值,否则返回实际值起到保护用户的隐私目的。
反射机制的相关类
与Java反射相关的类如下:
| 类名 | 用途 |
|---|---|
| Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
| Field类 | 代表类的成员变量(成员变量也称为类的属性) |
| Method类 | 代表类的方法 |
| Constructor类 | 代表类的构造方法 |
Class类
Class代表类的实体,在运行的Java应用程序中表示类和接口。在这个类中提供了很多有用的方法,这里对他们简单的分类介绍。
- 获得类相关的方法
| 方法 | 用途 |
|---|---|
| asSubclass(Class clazz) | 把传递的类的对象转换成代表其子类的对象 |
| Cast | 把对象转换成代表类或是接口的对象 |
| getClassLoader() | 获得类的加载器 |
| getClasses() | 返回一个数组,数组中包含该类中所有公共类和接口类的对象 |
| getDeclaredClasses() | 返回一个数组,数组中包含该类中所有类和接口类的对象 |
| forName(String className) | 根据类名返回类的对象 |
| getName() | 获得类的完整路径名字 |
| newInstance() | 创建类的实例 |
| getPackage() | 获得类的包 |
| getSimpleName() | 获得类的名字 |
| getSuperclass() | 获得当前类继承的父类的名字 |
| getInterfaces() | 获得当前类实现的类或是接口 |
- 获得类中属性相关的方法
| 方法 | 用途 |
|---|---|
| getField(String name) | 获得某个公有的属性对象 |
| getFields() | 获得所有公有的属性对象 |
| getDeclaredField(String name) | 获得某个属性对象 |
| getDeclaredFields() | 获得所有属性对象 |
- 获得类中注解相关的方法
| 方法 | 用途 |
|---|---|
| getAnnotation(Class annotationClass) | 返回该类中与参数类型匹配的公有注解对象 |
| getAnnotations() | 返回该类所有的公有注解对象 |
| getDeclaredAnnotation(Class annotationClass) | 返回该类中与参数类型匹配的所有注解对象 |
| getDeclaredAnnotations() | 返回该类所有的注解对象 |
- 获得类中构造器相关的方法
| 方法 | 用途 |
|---|---|
| getConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的公有构造方法 |
| getConstructors() | 获得该类的所有公有构造方法 |
| getDeclaredConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的构造方法 |
| getDeclaredConstructors() | 获得该类所有构造方法 |
- 获得类中方法相关的方法
| 方法 | 用途 |
|---|---|
| getMethod(String name, Class…<?> parameterTypes) | 获得该类某个公有的方法 |
| getMethods() | 获得该类所有公有的方法 |
| getDeclaredMethod(String name, Class…<?> parameterTypes) | 获得该类某个方法 |
| getDeclaredMethods() | 获得该类所有方法 |
- 类中其他重要的方法
| 方法 | 用途 |
|---|---|
| isAnnotation() | 如果是注解类型则返回true |
| isAnnotationPresent(Class<? extends Annotation> annotationClass) | 如果是指定类型注解类型则返回true |
| isAnonymousClass() | 如果是匿名类则返回true |
| isArray() | 如果是一个数组类则返回true |
| isEnum() | 如果是枚举类则返回true |
| isInstance(Object obj) | 如果obj是该类的实例则返回true |
| isInterface() | 如果是接口类则返回true |
| isLocalClass() | 如果是局部类则返回true |
| isMemberClass() | 如果是内部类则返回true |
Field类
Field代表类的成员变量(成员变量也称为类的属性)。
| 方法 | 用途 |
|---|---|
| equals(Object obj) | 属性与obj相等则返回true |
| get(Object obj) | 获得obj中对应的属性值 |
| set(Object obj, Object value) | 设置obj中对应属性值 |
Method类
Method代表类的方法。
| 方法 | 用途 |
|---|---|
| invoke(Object obj, Object… args) | 传递object对象及参数调用该对象对应的方法 |
Constructor类
Constructor代表类的构造方法。
| 方法 | 用途 |
|---|---|
| newInstance(Object… initargs) | 根据传递的参数创建类的对象 |
示例
为了演示反射的使用,首先构造一个与书籍相关的model——Book.java,然后通过反射方法示例创建对象、反射私有构造方法、反射私有属性、反射私有方法,最后给出两个比较复杂的反射示例——获得当前ZenMode和关机Shutdown。
- 被反射类Book.java
public class Book{ private final static String TAG = "BookTag";
private String name; private String author;
@Override public String toString() { return "Book{" + "name='" + name + '\'' + ", author='" + author + '\'' + '}'; }
public Book() { }
private Book(String name, String author) { this.name = name; this.author = author; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getAuthor() { return author; }
public void setAuthor(String author) { this.author = author; }
private String declaredMethod(int index) { String string = null; switch (index) { case 0: string = "I am declaredMethod 1 !"; break; case 1: string = "I am declaredMethod 2 !"; break; default: string = "I am declaredMethod 1 !"; }
return string; }}- 反射逻辑封装在ReflectClass.java
public class ReflectClass { private final static String TAG = "peter.log.ReflectClass";
// 创建对象 public static void reflectNewInstance() { try { Class<?> classBook = Class.forName("com.android.peter.reflectdemo.Book"); Object objectBook = classBook.newInstance(); Book book = (Book) objectBook; book.setName("Android进阶之光"); book.setAuthor("刘望舒"); Log.d(TAG,"reflectNewInstance book = " + book.toString()); } catch (Exception ex) { ex.printStackTrace(); } }
// 反射私有的构造方法 public static void reflectPrivateConstructor() { try { Class<?> classBook = Class.forName("com.android.peter.reflectdemo.Book"); Constructor<?> declaredConstructorBook = classBook.getDeclaredConstructor(String.class,String.class); //将构造方法设置成可以访问的 declaredConstructorBook.setAccessible(true); Object objectBook = declaredConstructorBook.newInstance("Android开发艺术探索","任玉刚"); Book book = (Book) objectBook; Log.d(TAG,"reflectPrivateConstructor book = " + book.toString()); } catch (Exception ex) { ex.printStackTrace(); } }
// 反射私有属性 public static void reflectPrivateField() { try { Class<?> classBook = Class.forName("com.android.peter.reflectdemo.Book"); Object objectBook = classBook.newInstance(); Field fieldTag = classBook.getDeclaredField("TAG"); //将私有属性设置成可以访问的 fieldTag.setAccessible(true); String tag = (String) fieldTag.get(objectBook); Log.d(TAG,"reflectPrivateField tag = " + tag); } catch (Exception ex) { ex.printStackTrace(); } }
// 反射私有方法 public static void reflectPrivateMethod() { try { Class<?> classBook = Class.forName("com.android.peter.reflectdemo.Book"); Method methodBook = classBook.getDeclaredMethod("declaredMethod",int.class); //将私有方法设置成可以访问的 methodBook.setAccessible(true); Object objectBook = classBook.newInstance(); String string = (String) methodBook.invoke(objectBook,0);
Log.d(TAG,"reflectPrivateMethod string = " + string); } catch (Exception ex) { ex.printStackTrace(); } }
// 获得系统Zenmode值 public static int getZenMode() { int zenMode = -1; try { Class<?> cServiceManager = Class.forName("android.os.ServiceManager"); Method mGetService = cServiceManager.getMethod("getService", String.class); Object oNotificationManagerService = mGetService.invoke(null, Context.NOTIFICATION_SERVICE); Class<?> cINotificationManagerStub = Class.forName("android.app.INotificationManager$Stub"); Method mAsInterface = cINotificationManagerStub.getMethod("asInterface",IBinder.class); Object oINotificationManager = mAsInterface.invoke(null,oNotificationManagerService); Method mGetZenMode = cINotificationManagerStub.getMethod("getZenMode"); zenMode = (int) mGetZenMode.invoke(oINotificationManager); } catch (Exception ex) { ex.printStackTrace(); }
return zenMode; }
// 关闭手机 public static void shutDown() { try { Class<?> cServiceManager = Class.forName("android.os.ServiceManager"); Method mGetService = cServiceManager.getMethod("getService",String.class); Object oPowerManagerService = mGetService.invoke(null,Context.POWER_SERVICE); Class<?> cIPowerManagerStub = Class.forName("android.os.IPowerManager$Stub"); Method mShutdown = cIPowerManagerStub.getMethod("shutdown",boolean.class,String.class,boolean.class); Method mAsInterface = cIPowerManagerStub.getMethod("asInterface",IBinder.class); Object oIPowerManager = mAsInterface.invoke(null,oPowerManagerService); mShutdown.invoke(oIPowerManager,true,null,true);
} catch (Exception ex) { ex.printStackTrace(); } }
public static void shutdownOrReboot(final boolean shutdown, final boolean confirm) { try { Class<?> ServiceManager = Class.forName("android.os.ServiceManager"); // 获得ServiceManager的getService方法 Method getService = ServiceManager.getMethod("getService", java.lang.String.class); // 调用getService获取RemoteService Object oRemoteService = getService.invoke(null, Context.POWER_SERVICE); // 获得IPowerManager.Stub类 Class<?> cStub = Class.forName("android.os.IPowerManager$Stub"); // 获得asInterface方法 Method asInterface = cStub.getMethod("asInterface", android.os.IBinder.class); // 调用asInterface方法获取IPowerManager对象 Object oIPowerManager = asInterface.invoke(null, oRemoteService); if (shutdown) { // 获得shutdown()方法 Method shutdownMethod = oIPowerManager.getClass().getMethod( "shutdown", boolean.class, String.class, boolean.class); // 调用shutdown()方法 shutdownMethod.invoke(oIPowerManager, confirm, null, false); } else { // 获得reboot()方法 Method rebootMethod = oIPowerManager.getClass().getMethod("reboot", boolean.class, String.class, boolean.class); // 调用reboot()方法 rebootMethod.invoke(oIPowerManager, confirm, null, false); } } catch (Exception e) { e.printStackTrace(); } }}- 调用相应反射逻辑方法
try { // 创建对象 ReflectClass.reflectNewInstance();
// 反射私有的构造方法 ReflectClass.reflectPrivateConstructor();
// 反射私有属性 ReflectClass.reflectPrivateField();
// 反射私有方法 ReflectClass.reflectPrivateMethod(); } catch (Exception ex) { ex.printStackTrace(); }
Log.d(TAG," zenmode = " + ReflectClass.getZenMode());Log输出结果如下:
08-27 15:11:37.999 11987-11987/com.android.peter.reflectdemo D/peter.log.ReflectClass: reflectNewInstance book = Book{name='Android进阶之光', author='刘望舒'}08-27 15:11:38.000 11987-11987/com.android.peter.reflectdemo D/peter.log.ReflectClass: reflectPrivateConstructor book = Book{name='Android开发艺术探索', author='任玉刚'}08-27 15:11:38.000 11987-11987/com.android.peter.reflectdemo D/peter.log.ReflectClass: reflectPrivateField tag = BookTag08-27 15:11:38.000 11987-11987/com.android.peter.reflectdemo D/peter.log.ReflectClass: reflectPrivateMethod string = I am declaredMethod 1 !08-27 15:11:38.004 11987-11987/com.android.peter.reflectdemo D/peter.log.ReflectDemo: zenmode = 0总结
总结反射案例用到的方法:
1.实例化Class类对象
Class<?> classu = Class.forName("reflect.User");2.获得某个类的全部属性
Field[] userFields = classu.getDeclaredFields();3.取消权限的访问控制(可以通过 获取私有的属性值)
userFields[i].setAccessible(true);4.得到属性的字段名
userFields[i].getName()5.将指定对象变量上(user) 此Field对象表示的字段设置为指定的新值。
userFields[i].set(user,map.get(s));6.通过反射实例化类的对象
User user = (User) classu.newInstance();7.通过反射机制调用某个类的方法
Method method = classu.getMethod();//参数:方法名 若方法有参数,加上参数类型的class对象 method.invoke();//参数:实例化出来的类对象,若方法有参数,加上值value本文列举了反射机制使用过程中常用的、重要的一些类及其方法,更多信息和用法需要近一步的阅读Google提供的相关文档和示例。
在阅读Class类文档时发现一个特点,以通过反射获得Method对象为例,一般会提供四种方法,getMethod(parameterTypes)、getMethods()、getDeclaredMethod(parameterTypes)和getDeclaredMethods()。getMethod(parameterTypes)用来获取某个公有的方法的对象,getMethods()获得该类所有公有的方法,getDeclaredMethod(parameterTypes)获得该类某个方法,getDeclaredMethods()获得该类所有方法。**带有Declared修饰的方法可以反射到私有的方法,没有Declared修饰的只能用来反射公有的方法。**其他的Annotation、Field、Constructor也是如此。
在ReflectClass类中还提供了两种反射PowerManager.shutdown()的方法,在调用的时候会输出如下log,提示没有相关权限。之前在项目中尝试反射其他方法的时候还遇到过有权限和没权限返回的值不一样的情况。如果源码中明确进行了权限验证,而你的应用又无法获得这个权限的话,建议就不要浪费时间反射了。
W/System.err: java.lang.reflect.InvocationTargetException W/System.err: at java.lang.reflect.Method.invoke(Native Method) W/System.err: at .ReflectClass.shutDown(ReflectClass.java:104) W/System.err: at .MainActivity$1.onClick(MainActivity.java:25) W/System.err: at android.view.View.performClick(View.java:6259) W/System.err: at android.view.View$PerformClick.run(View.java:24732) W/System.err: at android.os.Handler.handleCallback(Handler.java:789) W/System.err: at android.os.Handler.dispatchMessage(Handler.java:98) W/System.err: at android.os.Looper.loop(Looper.java:164) W/System.err: at android.app.ActivityThread.main(ActivityThread.java:6592) W/System.err: at java.lang.reflect.Method.invoke(Native Method) W/System.err: at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769) W/System.err: Caused by: java.lang.SecurityException: Neither user 10224 nor current process has android.permission.REBOOT. W/System.err: at android.os.Parcel.readException(Parcel.java:1942) W/System.err: at android.os.Parcel.readException(Parcel.java:1888) W/System.err: at android.os.IPowerManager$Stub$Proxy.shutdown(IPowerManager.java:787) W/System.err: ... 12 more项目中反射的使用案例1
1、主要用到类介绍
1.1、方法参数
@Data@Builderpublic class Command { private String method; private JSONObject params;}1.2、方法集合接口
@Validatedpublic interface Service {
/** * 用户注册 * * @param bizUserId 用户ID * @return 返回信息 * @throws IOException 异常 */ String createMember(@NotNull String bizUserId) throws IOException;}1.3、方法接口实现类
调用的发送请求的方法,RequestFactory去构建出一个统一参数对象RequestDTO
public class ServiceImpl implements Service {
@Override public String createMember(String bizUserId) throws IOException { return new YunHttpClient().post(RequestFactory.registerMember(bizUserId, RegisterMemberRq.Source.Mobile)); }}1.4、发送请求方法
/** * YunHttpClient * * @author zhengyong * @date 2019/5/16 */@Slf4jpublic class YunHttpClient extends BaseClient {
/** * 封装的post请求方法 * @param entity 请求体 * @param <T> 请求参数 * @return 返回信息 * @throws IOException io异常 */ public <T> String post(RequestDTO<T> entity) throws IOException { StringBuilder result = new StringBuilder(); BufferedWriter writer = null; BufferedReader reader = null; log.info("发送通联请求参数,{}", JSON.toJSONString(entity)); String data; try { //自定义编码签名 data = urlEncode(entity); } catch (Exception e) { throw new IOException(e); } try { URL httpUrl = new URL(TonglianContext.getServerUrl()); HttpURLConnection connection = (HttpURLConnection)httpUrl.openConnection(); connection.setRequestProperty("Connection", "keep-alive"); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); connection.setRequestMethod("POST"); connection.setDoOutput(true); connection.setDoInput(true); writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream(), StandardCharsets.UTF_8)); writer.write(data); writer.flush(); reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8)); String line; while ((line = reader.readLine()) != null) { result.append(line); } } finally { IOUtils.close(writer); IOUtils.close(reader); } log.info("【通联同步返回参数】:{}",result.toString()); ResponseDTO resp = JSON.parseObject(result.toString(), ResponseDTO.class); resp.verify(); if (resp.isSuccees()) { return resp.getSignedValue(); } else { throw new ApiException(resp.getErrorCode(), resp.getMessage()); } }
/** * 封装的get请求方法 * @param entity 请求体 * @param <T> 请求参数 * @return 返回信息 * @throws IOException io异常 */ public <T> String get(RequestDTO<T> entity) throws IOException { StringBuilder result = new StringBuilder(); BufferedReader reader = null; String data; try { data = urlEncode(entity); } catch (Exception e) { throw new IOException(e); } try { URL httpUrl = new URL(TonglianContext.getServerUrl() + "?" + data); HttpURLConnection connection = (HttpURLConnection)httpUrl.openConnection(); connection.setRequestProperty("Connection", "keep-alive"); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); connection.setRequestMethod("GET"); connection.setDoOutput(true); reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
String line; while ((line = reader.readLine()) != null) { result.append(line); } } finally { IOUtils.close(reader); } ResponseDTO resp = JSON.parseObject(result.toString(), ResponseDTO.class).verify(); if (resp.isSuccees()) { return resp.getSignedValue(); } else { throw new ApiException(resp.getErrorCode(), resp.getMessage()); } }}1.5、根据实际情况封装的请求对象
/** * RequestDTO 请求DTO * * @author zhengyong * @date 2019/5/16 */@Data@Builderpublic class RequestDTO<T> { /** * 通联分配id */ private String sysid; /** * 时间戳 */ private Date timestamp; /** * 版本号 */ private String v; /** * 请求参数 */ private RqWrapper<T> req;
}
/** * RqWrapper * 请求包装器 * @author zhengyong * @date 2019/5/20 */@Data@Builderpublic class RqWrapper<T> { /** * 服务对象 */ private String service; /** * 调用方法 */ private String method; /** * 参数 */ private T param;}1.6、RequestFactory
public class RequestFactory {
private RequestFactory() {
}
/** * 用户注册 * * @param bizUserId 业务系统用户ID * @param type 类型 * @return 注册信息 */ public static RequestDTO<RegisterMemberRq> registerMember(String bizUserId, RegisterMemberRq.Source type) { //构建指定类型的请求参数 RegisterMemberRq member = RegisterMemberRq.builder().bizUserId(bizUserId) .memberType(RegisterMemberRq.MenberType.Personal.getType()).source(type.getSource()).build(); return build(member, "createMember", "MemberService"); }
private static <T> RequestDTO<T> build(T t, String method, String service) { //组装 RqWrapper,并设置到 RequestDTO中 RqWrapper<T> re = RqWrapper.<T>builder().method(method).service(service).param(t).build(); return RequestDTO.<T>builder().sysid(TonglianContext.getSysId()).timestamp(new Date()).v("2.0").req(re).build(); }1.7、TonglianAdapter 适配器
@Validatedpublic interface TonglianAdapter {
/** * 执行方法 * @param cmd 命令 * @return 结果 */ String excute(Command cmd);}1.8、TonglianAdapterImpl
1、创建 时,在构造器中注入了 service
2、使用反射,执行command参数中指定的方法
3、类型转换器 中去取出不同类型的参数
- jo.getJSONArray(name)
- jo.getJSONObject(name)
- jo.getString(name)
- jo.getLong(name)
- jo.get(name)
4、调用反射,执行,返回string
<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);
来说,参数supplier 是一个生成目标类型实例的方法,代表着目标容器是什么;
accumulator是将操作的目标数据填充到supplier 生成的目标类型实例中去的方法,代表着如何将元素添加到容器中;
而combiner是将多个supplier 生成的实例整合到一起的方法,代表着规约操作,将多个结果合并。@Slf4jpublic class TonglianAdapterImpl implements TonglianAdapter {
private Service service;
private OrderService orderService;
public TonglianAdapterImpl(AdapterProperties adapterProperties) { TonglianContext.init(adapterProperties); service = new ServiceImpl(); orderService = new OrderServiceImpl(); }
@Override public String excute(Command cmd) { //去取所有方法 Method[] methods = Service.class.getDeclaredMethods(); for (Method me : methods) { //匹配传进来的方法名字 if (me.getName().equals(cmd.getMethod())) { //获取方法的所有参数 Parameter[] params = me.getParameters(); //来说,参数supplier 是一个生成目标类型实例的方法,代表着目标容器是什么; // accumulator是将操作的目标数据填充到supplier 生成的目标类型实例中去的方法,代表着如何将元素添加到容器中; // 而combiner是将多个supplier 生成的实例整合到一起的方法,代表着规约操作,将多个结果合并。 //将参数转为数组,并获取参数类型,参数名字,typeTransformer去转换出统一的Object参数 ArrayList<Object> objList = Arrays.stream(params).collect //声明创建ArrayList (ArrayList::new, //BiConsumer 接口接收两个泛型参数 a:list,b:Parameter (a, b) -> { a.add(typeTransformer(cmd.getParams(), b.getType(), b.getName())); }, //合并 (a, b) -> a.addAll(b)); try { //反射调用,service在类实例化的时候已经被传入进来 return (String) me.invoke(service, objList.toArray(new Object[objList.size()])); } catch (InvocationTargetException e1){ Throwable targetException = e1.getTargetException(); if(targetException instanceof ApiException) { throw (ApiException) targetException; } throw new RuntimeException(e1); } catch(IllegalAccessException e) { throw new RuntimeException(e); } } } throw new RuntimeException("excute:CMD Method Error。。。。"); }
/** * 类型转换器 * @param jo JSONObject * @param type 类型 * @param name 名字 * @param <T> 对应类型 * @return 对应类型 */ private <T> Object typeTransformer(JSONObject jo, Class<T> type, String name) { if (type.equals(Long.class)) { return jo.getLong(name); } else if (type.equals(PayType.class)) { return PayType.valueOf(jo.getString(name)); } else if (type.equals(ValidateType.class)) { return ValidateType.valueOf(jo.getString(name)); } else if (type.equals(AuthType.class)) { return AuthType.valueOf(jo.getString(name)); } else if (type.equals(WechatConfig.AppType.class)) { return WechatConfig.AppType.valueOf(jo.getString(name)); } else if (type.equals(JSONObject.class)) { return jo.getJSONObject(name); } else if (type.equals(JSONArray.class)) { return jo.getJSONArray(name); } else { return jo.get(name); } }}2、整体架构图

如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时