首页
归档
友情链接
关于
Search
1
在wsl2中安装archlinux
80 阅读
2
nvim番外之将配置的插件管理器更新为lazy
58 阅读
3
2018总结与2019规划
54 阅读
4
PDF标准详解(五)——图形状态
33 阅读
5
为 MariaDB 配置远程访问权限
30 阅读
心灵鸡汤
软件与环境配置
博客搭建
从0开始配置vim
Vim 从嫌弃到依赖
archlinux
Emacs
MySQL
Git与Github
AndroidStudio
cmake
读书笔记
菜谱
编程
PDF 标准
从0自制解释器
qt
C/C++语言
Windows 编程
Python
Java
算法与数据结构
PE结构
登录
Search
标签搜索
c++
c
学习笔记
windows
文本操作术
编辑器
NeoVim
Vim
win32
VimScript
Java
emacs
linux
文本编辑器
elisp
反汇编
OLEDB
数据库编程
数据结构
内核编程
Masimaro
累计撰写
308
篇文章
累计收到
27
条评论
首页
栏目
心灵鸡汤
软件与环境配置
博客搭建
从0开始配置vim
Vim 从嫌弃到依赖
archlinux
Emacs
MySQL
Git与Github
AndroidStudio
cmake
读书笔记
菜谱
编程
PDF 标准
从0自制解释器
qt
C/C++语言
Windows 编程
Python
Java
算法与数据结构
PE结构
页面
归档
友情链接
关于
搜索到
1
篇与
的结果
2019-08-18
Java反射
Java中的类文件最终会被编译为.class 文件,也就是Java字节码。这个字节码中会存储Java 类的相关信息。在JVM执行这些代码时首先根据 java 命令中指定的类名找到.class 文件然后使用类加载器将class字节码文件加载到内存,在加载时会调用Class类的classLoader方法,读取.class 文件中保存类的成员变量、方法、构造方法,并将这些内容在需要时创建对应的对象。这个就是java中的反射机制。反射机制提供了由字符串到具体类对象的映射,提高了程序的灵活性,在一些框架中大量使用映射,做到根据用户提供的xml配置文件来动态生成并创建类对象反射机制最关键的就是从字节码文件中加载类信息并封装为对应的结构。在Java中专门提供了一个 Class 类,用于存储从.class 文件中读取出来的类的信息。 该类的定义和常用方法如下:public final class Class<?> extends Object implements Serializable, GenericDeclaration, Type, AnnotatedElement{ String getName(); //获取类名 ClassLoader getClassLoader(); //返回类的加载器 static Class<T> forName(String className); //根据类名返回对应类的Class对象 Field getField(String name); //根据名称返回对应的Filed对象 Field[] getFields(); //返回所有的Filed 对象 Field getDeclaredField(String name) //;返回一个 Field对象。 Field[] getDeclaredFields();//返回的数组 Field对象 Constructor<T> getConstructor(Class<?>... parameterTypes); Constructor<?>[] getConstructors(); Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes); Constructor<?>[] getDeclaredConstructors(); Method getDeclaredMethod(String name, Class<?>... parameterTypes); Method[] getDeclaredMethods(); Method getMethod(String name, Class<?>... parameterTypes); Method[] getMethods(); }获取 Class 对象获取Class对象常见的有3种:可以通过 Class 类的静态方法 forName 传入类名获取可以通过具体对象的getClass 方法获取,这种方式的前提是我们拿到了目标对象,也就是需要内存中已经加载了对应的对象,相对来说第一种方法相对方便。通过类的静态class 成员来获取。下面是3中方式对应的代码 //1. 使用forName 来获取 try { Class<?> student = Class.forName("Student"); System.out.println(student.getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } //2. 使用getClass 对象 Class<? extends Student> aClass = new Student().getClass(); System.out.println(aClass.getName()); //3. 使用class 静态变量 Class<Student> studentClass = Student.class; System.out.println(studentClass.getName());需要注意的是在每个进程中 一个类的 Class 只有一个,拿上面的代码来说,即使 我们获取了3次,在内存中只有一个对应的Class 对象。获取类成员变量通过一定的方法,我们已经获取到了对应的Class 成员,之前说过Class是对字节码中记录的类信息的封装,类的成员变量被封装到了Field对象中,我们可以使用上述4个与Field有关的方法来获取对应的成员变量。public class Student { public String name; private int age; public String sex; private float gress; } //main try { Class<?> student = Class.forName("Student"); Field name = student.getField("name"); System.out.println(name.getName()); Field[] fields = student.getFields(); for (Field field: fields) { System.out.println(field.getName()); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); }上述的代码执行后会发现只能得到两个变量名,这两个函数只能获取 public 修饰的变量。要获取所有的可以使用 getDeclaredField(s) 函数组获取类方法Class 对象将类方法的信息封装到了 Method 对象中。我们可以使用 Method 对应的获取方法,同样的对应的Declared 方法能获取所有的,其他的只能获取公共的。这次我们实现一个 给Java Bean对象赋值的通用类。Java Bean是指满足这样一些条件的标准Java类:类必须被public 修饰类必须提供对应的getter 与 setter方法类必须提供空参的构造方法成员变量必须用private 修饰为了方便代码的编写,针对Java bean对象的getter/setter 方法命名有一个规定,尽量使用 get + 成员变量名(第一个字母大写)的方式来命名。同时定义类的属性值是 getter/setter 方法名去掉get/set 并将剩余词第一个字母小写得到属性名。针对这些定义,我们来实现一个根据字典值来给Java Bean赋值的方法。//默认已经给上述的student类添加了对应的getter/setter 方法,并且为了方便将所有成员都改为String static void BeanPopulate(Object bean, Map properties) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Iterator iterator = properties.entrySet().iterator(); while(iterator.hasNext()){ Map.Entry entry = (Map.Entry)iterator.next(); String key = (String) entry.getKey(); //首字母转大写 char[] chars = key.toCharArray(); chars[0] = (char) (chars[0] + ('A' - 'a')); String name = "set" + new String(chars); Method method = bean.getClass().getMethod(name, String.class); //第二个参数是方法的参数列表 method.invoke(bean, entry.getValue()); ////第一个参数是对象,第二个是方法的参数列表 } } Student student = new Student(); HashMap<String, String> map = new HashMap<>(); map.put("name", "tom"); map.put("age", "23"); map.put("sex", "男"); map.put("gress", "89.9"); try { BeanPopulate(student, map); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); }通过Class创建对象上述的方法还有 Constructor 函数组没有说,这个函数组用来获取类的构造方法,有了这个方法,我们就可以创建对象了,那么我们将上面的例子给改一改,实现动态创建类并根据传入的map来设置值static Object BeanPopulate(Class beanClass, Map properties) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { Iterator iterator = properties.entrySet().iterator(); Constructor constructor = beanClass.getConstructor(null); //构造方法的参数列表 Object bean = constructor.newInstance(null); //根据构造方法创建一个对象 while(iterator.hasNext()){ Map.Entry entry = (Map.Entry)iterator.next(); String key = (String) entry.getKey(); char[] chars = key.toCharArray(); chars[0] = (char) (chars[0] + ('A' - 'a')); String name = "set" + new String(chars); Method method = bean.getClass().getMethod(name, String.class); method.invoke(bean, entry.getValue()); } return bean; }
2019年08月18日
3 阅读
0 评论
0 点赞