java反射必知必会

版权声明:【分享也是一种提高】个人转载请在正文开头明显位置注明出处,未经作者同意禁止企业/组织转载,禁止私自更改原文,禁止用于商业目的。 https://blog.csdn.net/u010887744/article/details/57428913
        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;
    }
}


欢迎个人转载,但须在文章页面明显位置给出原文连接;
未经作者同意必须保留此段声明、不得随意修改原文、不得用于商业用途,否则保留追究法律责任的权利。

【 CSDN 】:csdn.zxiaofan.com
【GitHub】:github.zxiaofan.com

如有任何问题,欢迎留言。祝君好运!
Life is all about choices! 
将来的你一定会感激现在拼命的自己!

没有更多推荐了,返回首页