java反射必知必会
来源:互联网 发布:广东电信设计院知乎 编辑:程序博客网 时间:2024/05/19 07:42
java反射在学习工作中时常使用,自己也利用反射做了一些工具(比如《利用反射打造自定义注解,自动校验或处理数据》),但一直对反射缺乏较为系统的了解。以下内容是慕课网教程《反射——Java高级开发必须懂的》的学习笔记,相关代码见github工程github.com/zxiaofan/JDK-Study,该项目主要用于学习JDK相关源码以及基础知识。当然,想要更为系统地直接地了解反射,还需要去研究源码,这也是以后必须要做的事情。
1、Class类的使用
1.1、面向对象世界里,万事外物皆对象。
起初,“面向对象”是专指在程序设计中采用封装、继承、多态等设计方法。
类是对象,类是java.lang.Class类的实例对象。
There is a class named Class:有一个类,其名字是Class, 其实例是每一个对象。
1.2、类的实例对象如何表示
// 私有构造方法,仅java虚拟机能创建Class的实例对象
private Class(ClassLoader loader) {
classLoader = loader;
}
任何一个类都是Class的实例对象,这个实例对象有3种表示方式:
public class Class_Basic1 { @SuppressWarnings("rawtypes") public static void main(String[] args) { // Fruit实例对象表示方式 Fruit fruit = new Fruit(); // 任何一个类都是Class的实例对象(成为该类的类类型),这个实例对象有3种表示方式: // ① 任何一个类都有一个隐含的静态成员变量 Class c1 = Fruit.class; // ② 类对象的getClass方法 Class c2 = fruit.getClass(); // c1/c2:Fruit类的类类型(class type) System.out.println(c1 == c2); // true // ③ forName Class c3 = null; try { c3 = Class.forName("java1.lang.reflect.Fruit"); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println(c2 == c3); // true // 通过类的类类型(c1、c2、c3)创建类的创建类的对象实例。 try { Fruit fruit2 = (Fruit) c1.newInstance(); // 需要有无参的构造方法 fruit2.getColour(); } catch (Exception e) { e.printStackTrace(); } }} class Fruit { void getColour() { System.out.println("Hi colour"); }}
2、java动态加载类
Class.forName("类全称"):表示了类的类类型;代表了动态加载类。
静态加载类:编译时加载的类
如:new创建对象
动态加载类:运行时加载的类
假设有一个方法
getColour(String className){
Class c=Class.forName("指定水果");
IFruit fruit2 = (IFruit) c1.newInstance();
fruit2.getColour();
}
如果我们想获得不同水果的颜色(或者说根据不同的类调用不同的执行方法getColour),只需传入指定水果类(需实现IFruit接口,重写getColour方法)的类全称即可。
3、java获取方法信息
/** * 通过反射获取Class相关信息. * * 获取类信息,需先获取类的类类型 Class c = obj.getClass(); * * @author xiaofan */public class ClassInfoUtil extends TestCase { /** * 测试打印方法信息. * */ public void testPrintClassMethodInfo() { Class c1 = int.class; Class c2 = String.class; Class c3 = void.class; System.out.println(c1.getName()); // 类的全称(int) System.out.println(c2.getName()); // java.lang.String System.out.println(c2.getSimpleName()); // 不包含包名的类名称(String) System.out.println(c3.getName()); // void // 基本数据类型、void关键字,都存在类类型 String str = "zxiaofan.com"; System.out.println("=====打印 " + str.getClass().getName() + " 的类信息====="); printClassMethodInfo(str); } /** * 测试打印成员变量信息. * */ public void testFieldInfo() { printFieldInfo(new Integer("1")); } /** * 测试打印构造函数信息. * */ public void testConstructorInfo() { printConstructorInfo(new Integer("1")); } /** * 打印任意类的信息(类的成员函数、成员变量). * */ @SuppressWarnings("rawtypes") public static void printClassMethodInfo(Object obj) { // 获取类信息,需先获取类的类类型 Class c = obj.getClass(); // 获取类名称 System.out.println("类全称是:" + c.getName()); // Method类,方法对象,一个成员对象就是一个Method对象; // getMethods()获取所有public的函数,包括父类继承而来的 // c.getDeclaredMethods()获取所有该类自己声明的方法(所有访问类型) Method[] ms = c.getMethods(); // c.getDeclaredMethods() System.out.println("类方法如下:"); for (int i = 0; i < ms.length; i++) { Method method = ms[i]; // 方法返回值类型的类类型 Class returnType = method.getReturnType(); System.out.print("__" + returnType.getName() + " "); // 方法名称 System.out.print(method.getName() + "("); // 获取参数类型(参数列表的类型的类类型) Class[] paramTypes = method.getParameterTypes(); for (Class class1 : paramTypes) { System.out.print(class1.getName() + ","); } System.out.println(")"); } } /** * 打印任意类的成员变量信息. * * 成员变量也是对象,java.lang.Field类封装了成员变量相关操作。 * * getFields():所有public的成员变量; * * getDeclaredFields():该类自己声明的(即所有)成员变量信息。 * */ @SuppressWarnings("rawtypes") public static void printFieldInfo(Object obj) { // 获取类信息,需先获取类的类类型 Class c = obj.getClass(); // Field[] fields=c.getFields(); Field[] fields = c.getDeclaredFields(); for (Field field : fields) { // 成员变量的类型的类类型 Class fieldType = field.getType(); String typeName = fieldType.getName(); // 成员变量的名称 String fieldName = field.getName(); System.out.println(typeName + " " + fieldName); } } /** * 打印任意类的构造函数信息. * * 构造函数也是对象。java.lang.Constructor封装了构造函数信息 * * getConstructors():所有public的构造函数 * * getDeclaredConstructors():所有构造函数 * * getEnclosingConstructor():类A构造函数定义了内部类InnerA,则通过InnerA的Class对象调用getEnclosingConstructor可获取类A的构造函数(不是构造函数列表) * */ @SuppressWarnings("rawtypes") public static void printConstructorInfo(Object obj) { // 获取类信息,需先获取类的类类型 Class c = obj.getClass(); // Constructor[] constructors = c.getConstructors(); // Constructor enclosingConstructor = c.getEnclosingConstructor(); Constructor[] constructors = c.getDeclaredConstructors(); for (Constructor constructor : constructors) { System.out.print(constructor.getName() + " ("); Class[] paramTypes = constructor.getParameterTypes(); for (Class class1 : paramTypes) { System.out.print(class1.getName() + ","); } System.out.println(")"); } }}
4、通过反射调用指定方法
方法名和参数列表唯一决定某个方法(method.invoke(对象,参数列表))
public class ClassMethod extends TestCase { /** * 使用Method.invoke调用方法. * */ public void testInvokemethod() { A a = new A(); Class c = a.getClass(); // 获取类的方法《--类信息《--类类型 // 方法:由名称和参数列表决定 // getMethod获取public方法 // try { // Method method = c.getDeclaredMethod("print", new Class[]{int.class, int.class}); Method method_int = c.getDeclaredMethod("print", int.class, int.class); // 等价于new Class[]{int.class, int.class} // 方法method没有返回值则返回null,否则需要强转 Object invokeReturn = method_int.invoke(a, new Object[]{10, 20}); // 等价于 a.print(10,20); System.out.println("强转:" + (int) invokeReturn); System.out.println("=========="); Method method_String = c.getDeclaredMethod("print", String.class, String.class); method_String.invoke(a, "hi", "zxiaofan"); // 即a.print("hi","zxiaofan") System.out.println("=========="); // Method method_NoParam = c.getDeclaredMethod("print", new Class[]{}); Method method_NoParam = c.getDeclaredMethod("print"); // 等价于("print", new Class[]{}) method_NoParam.invoke(a, new Object[]{}); method_NoParam.invoke(a); // 等价于invoke(a, new Object[]{}) } catch (Exception e) { e.printStackTrace(); } } /** * 反射与泛型. * * 通过反射插入集合的非相同类型的数据,只能直接处理Object或对Object强转到实际类型。 */ @SuppressWarnings("rawtypes") public void testGeneric() { List list0 = new ArrayList<>(); List<String> list = new ArrayList<>(); list.add("hi"); // list.add(123); // 编译报错 Class c0 = list0.getClass(); Class c = list.getClass(); assertEquals(c0, c); // true // c0==c1说明:编译之后集合的泛型是去泛型化的;java中的泛型是防止错误输入的,只在编译阶段有效,编译后无效 // 通过方法的反射绕过编译 Method method; try { method = c.getMethod("add", Object.class); method.invoke(list, 456); // 绕过编译操作就绕过了泛型 } catch (Exception e) { e.printStackTrace(); } for (Object obj : list) { // 这样遍历是可以的 System.out.println(obj); } System.out.println("======"); for (String str : list) { System.out.println(str); // 不能这样遍历,Iterator迭代也不行 // str为int时抛异常:java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String } }} class A { public void print() { // 无参无返回值 System.out.println("hi zxiaofan.com"); } public String print(String a, String b) { // 参数String返回String String c = a + b; System.out.println(c); return c; } public int print(int a, int b) { // 参数int返回int int c = a + b; System.out.println(c); return c; }}
0 0
- java反射必知必会
- 【反射】JAVA反射机制
- JAVA 反射
- java 反射
- Java反射
- java反射
- java反射
- JAVA反射
- java 反射
- Java 反射
- java 反射
- Java反射
- java反射
- JAVA 反射
- java 反射
- Java反射
- java反射
- java 反射
- 分类器性能指标之ROC曲线、AUC值
- RCNN系列学习笔记(4):Faster R-CNN
- 《C++Primer》读书笔记(五)语句
- servlet/filter/listener/interceptor区别与联系
- Java读写Excel之POI入门
- java反射必知必会
- mybatis入门级对数据库增删查改
- eclipse如何配置环境变量
- JavaSE_38th_Comparable接口
- 异步写入文件
- 社交媒体(朋友圈、微博、QQ空间)开发一网打尽,PC端移动端都有!——源码来袭!
- java数据类型转换____Xstream框架对象和XML的转换
- 自定义注解 1
- 【Android与Cordova插件】Cordova插件的调试方案