java 反射
来源:互联网 发布:Java web 登录实现 编辑:程序博客网 时间:2024/05/16 10:19
使用场景
web中我不太清楚,android中,热修复时的原理,其实就是用的java反射,但不管咋样,学java的,了解java反射非常有必要!
什么是反射
反射定义
java官方文档给出了解释:
Reflection is the ability of a program to query and modify its state during the execution.
意为:反射是在程序运行时,能动态查看和修改它的状态。
在java中,我们能在程序运行时,获取它的属性,方法,修饰符,以及此类的父类。我们也能够在程序运行时,创建一个未知类的实例,并且设置或获取它的属性方法。
但是,在java中,我们不能在运行时改变它的数据结构,比如说,我们不能在程序运行时,往一个类或者对象里添加新的方法,也不能改变类中方法的代码。
反射API
反射中经常用到的几个类,如下所示:
类名 描述 java.lang.Class 表示在JVM中被类加载器加载的类。 java.lang.reflect.Field 表示一个类或者接口的属性。 java.lang.reflect.Constructor 表示一个类中的构造方法。 java.lang.reflect.Method 表示一个类或者接口中的方法。 java.lang.reflect.Modifier 解码一个类及其成员的访问修饰符。 java.lang.reflect.Array 程序运行时创建数组。具体用途
- 获取对象类名;
- 获取包名,修饰符等等;
- 获取类中定义的方法,返回类型,修饰符,参数类型,参数名等等;
- 获取所有构造函数;
- 用它其中一个构造方法创建类;
- 通过方法名和方法参数类型调用方法;
- 在运行时动态创建数组,并动态操作此数组元素。
反射相关类的使用
java.lang.Class
先上代码:
package com.lxh;public class MyClass { static { System.out.println("Loading class MyClass..."); }}
package com.lxh;public class Main { public static void main(String[] args) { try { String className = "com.lxh.MyClass"; boolean initialize = false; ClassLoader cLoader = Main.class.getClassLoader(); Class c = Class.forName(className, initialize, cLoader); className = "com.lxh.MyClass"; System.out.println("about to load"); // Will load and initialize the class c = Class.forName(className, true, cLoader); } catch (ClassNotFoundException e) { System.out.println(e.getMessage()); } }}
log如下:
about to loadLoading class MyClass...
Class.forName(String name, boolean initialize, ClassLoader loader)如果布尔值为false,表示不初始化名为name的类,当为true时,就会初始化。Class.forName(String name)其实也是调用的Class.forName(String name, boolean initialize, ClassLoader loader),只不过它中间默认的布尔值为true。当调用名为name的类时,name类中的静态代码块被加载。
注意:这里第一个参数name,必须是类的全名,包含包名,否则将调用不到该类。
java.lang.reflect.Field
反射类Field表示类中的属性,Field中有如下几种方法:
Field[] getFields()Field[] getDeclaredFields()Field getField(String name)Field getDeclaredField(String name)
getFields()表示所有该类所有修饰符为public的属性,以及该类所继承的父类所有修饰符为public的属性。
getDeclaredFields()表示该类任何修饰符的所有属性,但不包括父类中属性。
上代码:
class MySuperClass { public int super_id = -1; private String super_name = "Unknown";}class MyClass extends MySuperClass{ private int id = -1; public String name = "Unknown";}public class Main { public static void main(String[] args) { Class<MyClass> c = MyClass.class; // 获取MyClass类中所有的属性 ArrayList<String> fieldsDesciption = getDeclaredFieldsList(c); System.out.println("Declared Fields for " + c.getName()); for (String desc : fieldsDesciption) { System.out.println(desc); } //获取MyClass类中修饰符为public,及其父类中属性 fieldsDesciption = getFieldsList(c); System.out.println("\nAccessible Fields for " + c.getName()); for (String desc : fieldsDesciption) { System.out.println(desc); } } public static ArrayList<String> getFieldsList(Class c) { Field[] fields = c.getFields(); ArrayList<String> fieldsList = getFieldsDesciption(fields); return fieldsList; } public static ArrayList<String> getDeclaredFieldsList(Class c) { Field[] fields = c.getDeclaredFields(); ArrayList<String> fieldsList = getFieldsDesciption(fields); return fieldsList; } public static ArrayList<String> getFieldsDesciption(Field[] fields) { ArrayList<String> fieldList = new ArrayList<>(); for (Field f : fields) { int mod = f.getModifiers() & Modifier.fieldModifiers(); //获取该属性的修饰符 public,int等等 String modifiers = Modifier.toString(mod); //获取该属性的类型 int,String等等 Class<?> type = f.getType(); String typeName = type.getSimpleName(); // 获取该属性名 String fieldName = f.getName(); //拼接后加到集合中 fieldList.add(modifiers + " " + typeName + " " + fieldName); } return fieldList; }}
打印的log如下:
Declared Fields for com.lxh.MyClassprivate int idpublic String nameAccessible Fields for com.lxh.MyClasspublic String namepublic int super_id
说明getDeclaredFields()
获取到了指定类中所有属性,而getFields()获取的是指定类及其父类中修饰符为public的属性。而我们在具体情境下,一般是用getDeclaredFields()方法比较多~
java.lang.reflect.Method
Method中有如下方法:
Method[] getMethods()Method[] getDeclaredMethods()Method getMethod(String name, Class... parameterTypes)Method getDeclaredMethod(String name, Class... parameterTypes)
跟Field类似,getMethods()返回该类中任何修饰符的方法,getDeclaredMethods()返回该类及其父类中修饰符为public的方法
上代码:
class MyClass<T> { public MyClass(int i, int j, String s) { } public MyClass(T t) { } public int getInt(String a) { return 0; }}public class Main { public static void main(String[] args) { Class<MyClass> c = MyClass.class; ArrayList<String> methodsDesciption = getDeclaredMethodsList(c); System.out.println("Declared Methods for " + c.getName()); for (String desc : methodsDesciption) { System.out.println(desc); } methodsDesciption = getMethodsList(c); System.out.println("\nMethods for " + c.getName()); for (String desc : methodsDesciption) { System.out.println(desc); } } public static ArrayList<String> getMethodsList(Class c) { Method[] methods = c.getMethods(); ArrayList<String> methodsList = getMethodsDesciption(methods); return methodsList; } public static ArrayList<String> getDeclaredMethodsList(Class c) { Method[] methods = c.getDeclaredMethods(); ArrayList<String> methodsList = getMethodsDesciption(methods); return methodsList; } public static ArrayList<String> getMethodsDesciption(Method[] methods) { ArrayList<String> methodList = new ArrayList<>(); for (Method m : methods) { String modifiers = getModifiers(m); Class returnType = m.getReturnType(); String returnTypeName = returnType.getSimpleName(); String methodName = m.getName(); String params = getParameters(m).toString(); String throwsClause = getExceptionList(m).toString(); methodList.add(modifiers + " " + returnTypeName + " " + methodName + "(" + params + ") " + throwsClause); } return methodList; } public static ArrayList<String> getParameters(Executable exec) { Parameter[] parms = exec.getParameters(); ArrayList<String> parmList = new ArrayList<>(); for (int i = 0; i < parms.length; i++) { int mod = parms[i].getModifiers() & Modifier.parameterModifiers(); String modifiers = Modifier.toString(mod); String parmType = parms[i].getType().getSimpleName(); String parmName = parms[i].getName(); String temp = modifiers + " " + parmType + " " + parmName; if (temp.trim().length() == 0) { continue; } parmList.add(temp.trim()); } return parmList; } public static ArrayList<String> getExceptionList(Executable exec) { ArrayList<String> exceptionList = new ArrayList<>(); for (Class<?> c : exec.getExceptionTypes()) { exceptionList.add(c.getSimpleName()); } return exceptionList; } public static String getModifiers(Executable exec) { int mod = exec.getModifiers(); if (exec instanceof Method) { mod = mod & Modifier.methodModifiers(); } else if (exec instanceof Constructor) { mod = mod & Modifier.constructorModifiers(); } return Modifier.toString(mod); }}
log打印如下:
java.lang.reflect.Constructor
跟Method和Field类似~
通过反射给方法赋值
直接上代码:
import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;class MyClass { public MyClass() { } private String name; public void setName(String name) { this.name = name; System.out.println("setName():"+name); } public String getName(){ return name; }}public class Main { public static void main(String[] args) { Class<MyClass> myClass = MyClass.class; try { //通过class.newInstance()实例化对象 MyClass p = myClass.newInstance(); //给对象中方法赋值 Method setName = myClass.getMethod("setName", String.class); setName.invoke(p, "luoxiaohui"); //获取赋值后getName()中的返回值,不需要参数. Method getName = myClass.getMethod("getName"); System.out.println(getName.invoke(p)); } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) { System.out.println(e.getMessage()); } }}
注意:getMethod(String methodName,Class… parameterType),第一个参数表示方法名,后面范型表示方法的需要传的值,这里一定要跟原来方法相匹配,有参数就传参数。比如setName()方法需要传字符串型,参数则为String.class,而getName()不需要传。如果多传或者少传参数,将对应不上类中的方法。
通过反射给属性赋值
前面我们提到的Field的方法getField()和getDeclaredField(),只是获取属性的修饰符,属性类型,属性名,这里来说说给属性具体赋值。
上代码:
import java.lang.reflect.Field;class MyClass { private String name = "Unknown"; public MyClass() { } public String toString() { return "name=" + this.name; }}public class Main { public static void main(String[] args) { Class<MyClass> my = MyClass.class; try { MyClass p = my.newInstance(); Field nameField = my.getDeclaredField("name"); //Field.setAccessible()方法要注意 nameField.setAccessible(true); String nameValue = (String) nameField.get(p); System.out.println("Current name is " + nameValue); nameField.set(p, "luoxiaohui"); nameValue = (String) nameField.get(p); System.out.println("New name is " + nameValue); } catch (InstantiationException | IllegalAccessException | NoSuchFieldException | SecurityException | IllegalArgumentException e) { System.out.println(e.getMessage()); } }}
注意:在获取到Class的Field属性后,记得调用方法Field.setAccessible(true),这样能保证不管该属性是public,private,还是缺省,都能修改它,如果没调用此方法,则只能修改修饰符为public的属性。
通过反射扩展数组
java.lang.reflect.Array中有两个方法
Object newInstance(Class<?> componentType, int arrayLength)Object newInstance(Class<?> componentType, int... dimensions)
前者表示实例化一个长度为arrayLength的数组,后者表示实例化一个数组矩阵,后者此篇暂时不讲。以前在书上看到说数组实例化后,是不能改变起长度的,不过,通过反射,还是可以滴~
上代码:
import java.lang.reflect.Array;import java.util.Arrays;public class Main { private static int[] ids = new int[2]; public static void main(String[] args) { ids = new int[2]; System.out.println(ids.length); System.out.println(Arrays.toString(ids)); //将已经实例化的数组ids扩展两个单位长度 ids = (int[]) expandBy(2); //给数组中某个对象赋值 ids[2] = 3; ids[0] = 5; System.out.println(ids.length); System.out.println(Arrays.toString(ids)); } public static Object expandBy(int increment) { Object newArray = null; //获取数组ids的长度 int oldLength = Array.getLength(ids); //定义新的长度 int newLength = oldLength + increment; Class<?> c = ids.getClass(); //此方法很重要,对实例化数组通过反射扩展其长度 newArray = Array.newInstance(c.getComponentType(), newLength); return newArray; }}
log打印如下:
2[0, 0]4[5, 0, 3, 0]
数组成功扩展!
关于java中反射已经讲完,欢迎各位交流指教!
- 【反射】JAVA反射机制
- JAVA 反射
- java 反射
- Java反射
- java反射
- java反射
- JAVA反射
- java 反射
- Java 反射
- java 反射
- Java反射
- java反射
- JAVA 反射
- java 反射
- Java反射
- java反射
- java 反射
- java 反射
- android 蛋糕图
- QString isEmpty isNull
- test
- 解决Toast快速点击,重复多次的问题
- ] *** Assertion failure in -[AFHTTPRequestSerializer 今天用AF的时候遇到了报这个错误
- java 反射
- sql 关联表查询 LEFT ON INNER ON RIGHT ON
- ext.net GridPanel 实现鼠标移动显示图片
- 揭秘深度强化学习
- SDUT1141面向对象程序设计上机练习二(函数模板)
- 静态Handler中调用Toast
- 前端学习Html篇(一)
- 织梦DedeCms网站首页不生成html文件动态显示方法
- 整理:OJ 测试数据