反射相关

学习目的

  1. 了解反射的概念与作用意义
  2. 掌握java提供的反射机制使用到的包和类
  3. 了解反射机制的实现原理与Spring框架的结合

一.反射

  1. 概念
    在日常开发中,通常的开发步骤是:程序员建立项目 --> 编写源代码 --> 编译得到.class字节码文件 --> java虚拟机JVM加载字节码文件 --> 执行运行。
    而反射的步骤则是:通过编译好的字节码文件 --> 创建字节码对象 --> 对编译后的文件进行操作,操作包括创建实例对象、读取或修改对象属性、获取和执行对象方法等。
  2. 实质
    反射对字节码文件内容的操作都基于"字节码对象",而对实例对象、属性、方法等也有专属的反射"类"对象。
  3. 原则
    一切皆对象。

1.1 java.lang.reflect反射包

  1. 定义
    提供用于获取类和对象的反射信息(字节码信息) 的类和接口。
  2. 实质
    提供操作字节码文件的"操作对象"。
  3. 反射常用接口
  • Type:Java中所有类型的公共高级接口
  1. 反射常用类
  • Class:所有类或接口的"类型";
  • Constructor:构造器类;
  • Field:属性类;
  • Method:方法类;
  • Modifier:修饰符类;
  1. 反射最重要方法
  • Object invoke(Object obj, Object... args):该方法属于Method类中的方法,obj为字节码对象创建出的一个实例对象;使用Method对象调用该方法意为 调用obj对象的该Method方法,并且方法的参数为...args。
         // 使用反射机制来调用一个对象的方法
         // 创建字节码对象
        Class userClass = Class.forName("com.java.service.User");
        // 通过字节码反射创建实例对象
        Object obj = userServiceClass.newInstance();
        // 获取字节码对象中的Method对象(实则为一个方法),通过"方法名"和参数的类型(重载根据参数列表区分)
        Method loginMethod = userClass.getDeclaredMethod("login", String.class, String.class);
        //Method loginMethod = userClass.getDeclaredMethod("login", int.class);
        // 调用方法4要素:Method方法对象,实例对象Obj,参数,返回值
        // 通过Method对象.invoke()执行obj对象的Method方法,参数为...
        Object retValue = loginMethod.invoke(obj, "admin","123123");
        System.out.println(retValue);

1.2 java.lang.reflect.Type接口

  1. 定义
    Type 是Java中所有"类型"的公共高级接口,包括原始类型、参数化类型、数组类型、类型变量和基本类型等。
  2. 实质
    "数据类型",包括类的类型、参数的类型、元素的类型、返回值的类型等等。

1.3 java.lang.Class<T>类

  1. 定义
    Class类表示Java应用程序中的类和接口,包括我们自定义的"class类" 和 "interface接口"等。Class类用于反射指的是字节码文件内容中代表的"类型",如public类的字节码文件名代表的就是该"类",是一个Class。Class还实现了Type接口。
  2. 实质
    Class类代表所有的"类" 和 "接口"。
  3. 特点
    Class没有公共构造方法(只有一个private的构造 类加载器的构造器),Class对象是在加载类时由Java虚拟机以及 通过调用类加载器中的defineClass方法自动构造的。
  4. 常用方法
  • String toString():将该Class对象转换为字符串,返回的字符串表示形式为 "class" / "interface" + 空格 + 该Class对象代表的完整类名;
  • Class<?> forName(String className):返回 给定字符串名的类或接口相关的 Class字节码对象,采用默认的类加载器;
  • Class<?> forName(String name, boolean initialize,ClassLoader loader):返回 给定字符串名的类或接口相关的 Class字节码对象,采用指定的类加载器,并有可能初始化该字节码对象;
  • T newInstance():创建此Class字节码对象所代表的类的一个新实例;
  • boolean isInstance(Object obj):判断obj对象是否 是该Class字节码对象代表的类的一个实例;
  • boolean isInterface():判定该Class字节码对象是否代表一个接口类型;
  • boolean isArray():判定该Class字节码对象是否代表一个数组类型;
  • boolean isPrimitive():判定该Class字节码对象是否代表一个基本类型;
  • boolean isAnnotation():判定该Class字节码对象是否代表一个注释类型;
  • String getName():返回该Class字节码对象所代表类的全(路径)类名;
  • String getSimpleName():返回该Class字节码对象所代表类的简类名;
  • ClassLoader getClassLoader():返回加载该Class字节码对象的类加载器;
  • Class<? super T> getSuperclass():返回该Class字节码对象所代表的类的父类或父接口;
  • Class<?>[] getInterfaces():返回该Class字节码对象所代表的类所实现的所有接口,使用数组存储;
  • int getModifiers():返回该Class字节码对象所代表的类的修饰符,返回的是表示该类修饰符的int数(需要配合Modifier类的toString()方法将其转换为字符串);
  • Class<?> getDeclaringClass():若该Class字节码对象是另一个类或接口的成员,返回该Class字节码对象的声明类或接口;
  • boolean isAnonymousClass():判断该Class字节码对象底层是否是内部类;
  • boolean isLocalClass():判断该Class字节码对象底层是否是native本地类;
  • Field getField(String name):返回一个Field对象,代表该Class字节码对象所代表的类或接口的"公共"成员属性;
  • Method getMethod(String name, Class<?>... parameterTypes):返回一个Method对象,根据指定的方法名和参数类型查找返回;
  • Constructor<T> getConstructor(Class<?>... parameterTypes):返回一个Constructor对象,根据参数类型查找返回(仅返回public构造器);
  • Field[] getDeclaredFields():返回一个Field数组对象,代表该Class字节码对象所代表的类或接口的所有成员属性(包括公开的私有的);
  • Method[] getDeclaredMethods():返回一组 包含了该字节码对象所有的Method方法对象;
  • Constructor<?>[] getDeclaredConstructors():返回一组 Constructor对象,包含了该字节码对象中的所有、构造器对象;
  • Field getDeclaredField(String name):返回一个 Field对象,根据指定的字段属性名来查找返回;
  • Method getDeclaredMethod(mName,pType...):返回一个Method方法对象,根据方法名、参数类型作为区分;
  • Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回一个任意修饰符的Constructor对象,根据参数类型查找返回;
  • java.net.URL getResource(String name):
  • T cast(Object obj):将指定obj对象强制转换成Class字节码对象所代表的类。
  1. 代码示例
//创建字节码对象
            Class c = Class.forName("com.yry.pratice.reflection.bean.User");
            System.out.println(c);
            //将字节码对象c换成字符串输出:Class或Interface 全类名
            String s = c.toString();
            System.out.println(s);
            //获取字节码对象所代表类的名称
            String name = c.getName();//全类名
            System.out.println(name);//com.yry.pratice.reflection.bean.User
            String simpleName = c.getSimpleName();//简类名
            System.out.println(simpleName);//User
            //由字节码对象 反射创建 实例对象s
            Object instance = c.newInstance();
            System.out.println(instance);//输出instance.toString()的执行结果
            //判断指定obj对象是否 该字节码对象的一个实例
            Object oo = new Object();
            boolean b = c.isInstance(oo);
            System.out.println(b);
            //获取加载该字节码对象的类加载器
            ClassLoader classLoader = c.getClassLoader();
            System.out.println(classLoader);//

            //获取该字节码对象的修饰符--public公开的修饰符
            int modifiers = c.getModifiers();//不同的int值代表不同的修饰符
            System.out.println(modifiers);//1
            //将int类型修饰符 转换成 String字符串表示
            String s1 = Modifier.toString(modifiers);
            System.out.println(s1);//1对应public

1.4 java.lang.reflect.Constructor<T>构造器类

  1. 定义
    Constructor提供关于类的单个构造方法的信息 以及对它的访问权限。
  2. 实质
    Constructor在反射中指的是Class字节码对象所代表类的构造器。
  3. 常用方法
  • Class<T> getDeclaringClass():返回Class字节码对象,返回声明此Constructor构造器 表示的Class"类"对象;
  • String getName():返回此构造方法的名称;
  • int getModifiers():返回此构造方法的修饰符(需要配合Modifier类的toString()方法将其转换成字符串);
  • Class<?>[] getParameterTypes():按声明顺序返回此构造方法参数列表中的 参数类型数组;
  • int getParameterCount():返回此构造方法参数列表中的 参数的个数;
  • Class<?>[] getExceptionTypes():返回一组 此构造方法抛出的所有异常类型数组;
  • boolean equals(Object obj):将此Constructor对象与obj对象进行比较是否相同,如果两个对象由相同的类声明并且具有相同的形参类型则是相同的。
  • int hashCode():返回此Constructor的哈希码,与此Constructor所代表的类的哈希码相同;
  • String toString():返回描述此构造器的字符串,构造方法唯一可能的修饰符是访问修饰符public、protected或private;
  • T newInstance(Object ... initargs):通过此构造方法所代表的类来 创建的新对象;
  • boolean isVarArgs():判断此构造方法是否带可变数量的参数;
  • T getAnnotation(Class<T> annotation):如果此构造器上 存在指定annotation.Class类型的注释,返回这些注释;
  • Annotation[] getDeclaredAnnotations():返回一组 直接存在于此构造器上的所有注释;
  1. 代码示例
            //创建字节码对象
            Class c = Class.forName("com.yry.pratice.reflection.bean.User");
            //获取该字节码对象的构造器
            Constructor[] constructors = c.getConstructors();
            for (Constructor con:constructors) {
                System.out.println(con.getModifiers());//构造器的修饰符
                System.out.println(con.getDeclaringClass());//声明该构造器的类
                System.out.println(con.getName());//构造器的名称
                //获取构造器的参数类型数组
                Class[] parameterTypes = con.getParameterTypes();
                for (Class cas: parameterTypes) {
                    System.out.println(cas.getClass());//构造器参数的类型
                    System.out.println(cas.getSimpleName());//构造器参数的名称
                }
            }

1.5 java.lang.reflect.Field属性类<重要掌握>

  1. 定义
    Field提供有关 类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类字段(静态字段)或实例字段。
  2. 实质
    Field指的是Class字节码对象所代表的类中的普通字段或属性,每一个字段或属性都是一个对象。
  3. 常用方法
  • Class<?> getDeclaringClass():返回声明此Field对象所表示字段的类或接口 的Class对象;
  • String getName():返回此Field对象所表示字段的名称;
  • int getModifiers():返回此Field对象所表示字段的修饰符;
  • boolean isEnumConstant():判断该Filed对象所表示的字段是否是枚举类型的元素;
  • Class<?> getType():返回此Field对象所表示字段的数据类型;
  • boolean equals(Object obj):判断两个字段对象obj与此Filed对象比较是否相同,如果两个对象由相同的类声明并且具有相同的名称和类型,则相同的;
  • int hashCode():返回此Field对象所表示字段的哈希地址;
  • String toString():返回该Field对象所表示字段的字符串表示形式(原字段的定义格式);
  • Object get(Object obj):从obj对象中获取 此Field表示的字段的值(obj对象需要拥有相同Filed表示的字段);
  • boolean getBoolean(Object obj):从obj对象中 获取一个静态或实例 boolean字段的值(相同用法可以获取其他数据类型字段的值);
  • void set(Object obj, Object value):将obj对象上此Field对象表示的字段 设置为指定的新值;
  • T getAnnotation(Class<T> annotation):如果此字段属性上 存在指定annotation.Class类型的注释,返回这些注释;
  1. 代码示例
            //创建字节码对象
            Class c = Class.forName("com.yry.pratice.reflection.bean.User");

            //获取该字节码对象的public公开的"字段对象"
            Field no = c.getField("no");//仅获取public字段
            System.out.println(no.getType().getSimpleName());//字段类型:int
            System.out.println(no.getName());//字段名/变量名:no
            //获取该字节码对象所有的"字段对象"
            Field[] declaredFields = c.getDeclaredFields();
            for (Field f: declaredFields) {
                System.out.println(f.getModifiers());//字段修饰符
                System.out.println(f.getType());//字段数据类型
                System.out.println(f.getName());//字段名或变量名
            }

1.6 java.lang.reflect.Method方法类<重要掌握>

  1. 定义
    Method提供关于 类或接口上单独某个方法的信息,以及如何访问该方法。所反映的方法可能是类方法或实例方法(包括抽象方法)。
  2. 实质
    Method指的是Class字节码对象所代表的类中的方法,即常用的自定义方法或普通方法 对象。
  3. 常用方法
  • Class<?> getDeclaringClass():返回声明此Method对象所表示方法的类或接口 的Class对象;
  • String getName():返回此Method对象所表示方法的名称;
  • int getModifiers():返回此Method对象所表示方法的修饰符(需要配合Modifier类的toString()方法将其转换为字符串);
  • Class<?> getReturnType():返回此Method对象所表示方法的返回值类型;
  • Class<?>[] getParameterTypes():返回一组 此Method对象所表示方法的参数(类型)列表;
  • int getParameterCount():返回此Method对象所表示方法的 参数个数;
  • Class<?>[] getExceptionTypes()::返回一组 此Method对象所表示方法抛出的 异常类型;
  • boolean equals(Object obj):判断两个方法对象 obj对象与此Method对象是否相同,两个对象代表的方法由相同的类声明 并具有相同的名称、形参类型和返回类型,则相同;
  • String toString():返回该Method对象的字符串表示形式(该Method对象所代表方法的定义格式);
  • boolean isVarArgs():判断此Method对象所表示方法是否有可变数量的参数;
  • T getAnnotation(Class<T> annotation):如果此Method对象所表示的方法上存在指定annotation.Class类型的注释,返回这些注释;
  • Annotation[] getDeclaredAnnotations():返回一组 直接存在于此Method对象所表示的方法上的所有注释。
  1. 代码示例
            //创建字节码对象
            Class c = Class.forName("com.yry.pratice.reflection.bean.User");
            //获取该字节码对象的"方法对象"
            Method[] methods = c.getMethods();
            for (Method me:methods) {
                System.out.println(me.getDeclaringClass().getSimpleName());//声明该方法的类
                System.out.println(me.getModifiers());//方法的修饰符
                System.out.println(me.getReturnType());//方法的返回值类型
                System.out.println(me.getName());//方法的名称
                Class<?>[] parameterTypes = me.getParameterTypes();//方法的参数列表
                for (Class cs:parameterTypes) {
                    System.out.println(cs.getClass().getSimpleName());//参数类型的名称
                    System.out.println(cs.getName());//参数的名称
                    //System.out.println(cs.getSimpleName());//参数的名称
                }
            }

1.7 java.lang.reflect.Modifier修饰符类

  1. 定义
    Modifier提供关于 类或接口上的字段、属性、方法的修饰符信息,Modifier类中提供的都是static方法和常量,直接使用类名.调用,可以对类和成员的访问修饰符进行解码。
  2. 特点
    修饰符集被表示为整数,用不同的位-位置 (bit position) 表示不同的修饰符,需要使用toString(位置)方法将位置转换为字符串(真正的修饰符表示)。
  3. 实质
    Modifier指的是Class字节码对象所代表的类中的修饰符,即常用的修饰符对象。
  4. 字段
  • int PUBLIC = 0x00000001:表示public修饰符的 int值,getModifiers()返回 1表示该修饰符为public;
  • int PRIVATE = 0x00000002:表示private修饰符的 int值,getModifiers()返回 2(以下同理:返回值是几对应不同的修饰符);
  • int PROTECTED = 0x00000004:表示protected修饰符的 int值,getModifiers()返回 4
  • int STATIC = 0x00000008:表示static修饰符的 int值,getModifiers()返回 8
  • int FINAL = 0x00000010:表示final修饰符的 int值,getModifiers()返回 10
  • int SYNCHRONIZED = 0x00000020:表示synchronized修饰符的 int值,getModifiers()返回 20
  • int VOLATILE = 0x00000040:表示volatile修饰符的 int值,getModifiers()返回 40
  • int TRANSIENT = 0x00000080:表示transient修饰符的 int值,getModifiers()返回 80
  • int NATIVE = 0x00000100:表示native修饰符的 int值,getModifiers()返回 100
  • int INTERFACE = 0x00000200:表示interface修饰符的 int值,getModifiers()返回 200
  • int ABSTRACT = 0x00000400:表示abstract修饰符的 int值,getModifiers()返回 400
  1. 常用方法
  • String toString(int mod):将getModifiers()返回的代表指定修饰符的int值 转换为字符串;
  • boolean isPublic(int mod):判断整数参数mod是否包括public修饰符;
  • boolean isXxx(int mod):判断整数参数mod是否包括Xxx修饰符。
  1. 代码示例
            //创建字节码对象,获取字节码文件
            Class c = Class.forName("com.yry.pratice.reflection.bean.User");
            //获取字节码中 Filed字段对象
            Field no = c.getField("no");
            //获取修饰Field字段的修饰符--返回的int值代表不同的修饰符
            int modifiers = no.getModifiers();
            System.out.println(modifiers);//返回int值为1
            //将返回的int值转换为对应修饰符的字符串表示
            String s = Modifier.toString(modifiers);
            System.out.println(s);//int值为1对应的修饰符为:Public
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容