Java进阶之反射
来源:互联网 发布:linux开放端口 编辑:程序博客网 时间:2024/05/20 15:41
1 什么是反射
反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。
一句话总结:反射就是把Java类中的各种成分通过java的反射API映射成相应的Java类,得到这些类以后就可以对其进行使用。比如方法,构造方法,成员变量,类型,包等。
反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。重点:是运行时而不是编译时
2 反射的主要用途
当我们在使用IDE(如Eclipse,IDEA)时,当我们输入一个对象或类并想调用它的属性或方法时,一按点号,编译器就会自动列出它的属性或方法,这里就会用到反射。
反射最重要的用途就是开发各种通用框架。
很多框架(比如Spring)都是配置化的(比如通过XML文件配置JavaBean,Action之类的),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射——运行时动态加载需要加载的对象。例如:
- 框架提供配置文件,用户可以配置,例如类名
- 读取用户的配置文件
//一定要用完整的路径,不是硬编码,而是运算出来的InputStream is = new FileInputStream("文件目录");Properties properties = new Properties();properties.load(is);String value = properties.getProperty("key");
- 通过反射加载对应的类,并且动态去使用
3 反射的基本运用
3.1 获得Class对象
(1)使用Class类的forName静态方法:
public static Class<?> forName(String className)// 在JDBC开发中常用此方法加载数据库驱动Class.forName(driver);
(2)直接获取某一个对象的class,比如:
Class<?> klass = int.class;Class<?> classInt = Integer.TYPE;
(3)调用某个对象的getClass()方法,比如:
StringBuilder str = new StringBuilder("123");Class<?> klass = str.getClass();
(4)判断是否为某个类的实例
一般地,我们用instanceof关键字来判断是否为某个类的实例。同时我们也可以借助反射中Class对象的isInstance()方法来判断是否为某个类的实例,它是一个Native方法:
public native boolean isInstance(Object obj);
3.2 创建对象
(1)使用Class对象的newInstance()方法来创建Class对象对应类的实例。
Class<?> c = String.class;Object str = c.newInstance();// 或者:UserBean where;Object item = where.getClass().newInstance();
(2)先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。
//获取String所对应的Class对象Class<?> c = String.class;//获取String类带一个String参数的构造器Constructor constructor = c.getConstructor(String.class);//根据构造器创建实例,constructor.newInstance();Object obj = constructor.newInstance("23333");
3.3 获取某个Class对象的方法集合
(1)getDeclaredMethods()方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
Class<?> c = methodClass.class;Object object = c.newInstance();Method[] declaredMethods = c.getDeclaredMethods();
(2)getMethods()方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。
Method[] methods = c.getMethods();
(3)getMethod方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象。
//获取methodClass类的add方法Method method = c.getMethod("add", int.class, int.class);
3.4 获取构造器Constructor
(1)得到所有的构造方法
Constructor<?>[] constructors = Class.forName("java.lang.String").getConstructors();
(2)得到指定参数的某一个构造方法
Constructor<?> constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
3.5 获取类的成员变量(字段)信息
(1)getFiled: 访问公有的成员变量;
(2)getDeclaredField:所有已声明的成员变量。但不能得到其父类的成员变量;
(3)getFileds和getDeclaredFields用法同上(参照Method)。
3.6 调用方法
当我们从类中获取了一个方法后,我们就可以用invoke()方法来调用这个方法。invoke方法的原型为:
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
public class test { Class<?> klass = methodClass.class; //创建methodClass的实例 Object obj = klass.newInstance(); //获取methodClass类的add方法 Method method = klass.getMethod("add",int.class,int.class); //调用method对应的方法 => add(1,4) Object result = method.invoke(obj,1,4); System.out.println(result);}
3.7 利用反射创建数组
数组在Java里是比较特殊的一种类型,它可以赋值给一个Object Reference。
public static void testArray() throws ClassNotFoundException { Class<?> cls = Class.forName("java.lang.String"); Object array = Array.newInstance(cls,25); //往数组里添加内容 Array.set(array,0,"hello"); Array.set(array,1,"Java"); Array.set(array,2,"fuck"); Array.set(array,3,"Scala"); Array.set(array,4,"Clojure"); //获取某一项的内容 System.out.println(Array.get(array,3)); }
其中的Array类为java.lang.reflect.Array类。我们通过Array.newInstance()创建数组对象,它的原型是:
public static Object newInstance(Class<?> componentType, int length) throws NegativeArraySizeException { return newArray(componentType, length); }
而newArray()方法是一个Native方法,它在Hotspot JVM里的具体实现我们后边再研究:
private static native Object newArray(Class<?> componentType, int length) throws NegativeArraySizeException;
4 实践
(1)基本使用参考:Java进阶之注解
(2)反射方式赋值
/** * 获取查询结果 */ private List<T> getQueryResult(Cursor cursor, T where) { ArrayList items = new ArrayList(); // 查询的对象 Object item; while (cursor.moveToNext()) { try { item = where.getClass().newInstance(); // 遍历映射集合(relationMap)的key:数据库表列名(colmunName) for (Object object : relationMap.entrySet()) { Map.Entry entry = (Map.Entry) object; // 得到数据库表列名 String colomunName = (String) entry.getKey(); // 然后以列名拿到:列名在游标的位置 Integer colmunIndex = cursor.getColumnIndex(colomunName); // 获取key对应的值:成员变量(Field对象) Field field = (Field) entry.getValue(); Class type = field.getType(); if (colmunIndex != -1) { if (type == String.class) { // 反射方式赋值(native方法),相当于item.setValue(cursor.getString(colmunIndex)); field.set(item, cursor.getString(colmunIndex)); } else if (type == Double.class) { field.set(item, cursor.getDouble(colmunIndex)); } else if (type == Integer.class) { field.set(item, cursor.getInt(colmunIndex)); } else if (type == Long.class) { field.set(item, cursor.getLong(colmunIndex)); } else if (type == byte[].class) { field.set(item, cursor.getBlob(colmunIndex)); } else { continue; } } } items.add(item); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } return items;}
5 注意使用
由于反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射。另外,反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
6 参考链接
深入解析Java反射(1) - 基础
深入解析Java反射(2) - invoke方法
JAVA面试-基础加强与巩固:反射、注解、泛型等
- java之反射进阶
- Java进阶之反射
- Java进阶之反射
- java进阶之java的反射机制
- Java进阶之reflection(反射机制)
- 【Java 进阶】Java 反射
- Kotlin进阶之反射
- Java进阶 反射
- JAVA反射进阶篇
- 【Java进阶】-Java反射机制
- JAVA进阶学习-反射机制
- Java 反射由浅入深 | 进阶必备
- Java进阶之reflection(反射机制)——反射概念与基础
- Java进阶之reflection(反射机制)——通过反射操作泛型,注解
- Java进阶之反射的简单应用:通过反射运行配置文件内容
- Java进阶之reflection(反射机制)——反射概念与基础
- Java进阶之reflection(反射机制)——反射概念与基础
- 进阶:Java Reflection (JAVA反射)详解
- 用哈希code 和RGB值代表颜色
- Python的List.pop()方法
- ViewPager之上传报名信息图片
- 解决CentOS7虚拟机无法上网并设置CentOS7虚拟机使用静态IP上网
- 实现window10于虚拟机的复制粘贴
- Java进阶之反射
- Numpy 和 matplotlib 学习记录
- ios的内购功能
- easyui中easyui-textbox在前台加载json动态生成下拉框
- $.ajax()实例
- 实验3.1 栈和队列
- 解决80端口占用
- 容器技术初学
- android中几个conetxt的区别