java反射

一、前置知识点

1、运行java程序需要java虚拟机(JVM)
2、我们编写的java代码需要被编译成.class文件
3、.class文件会被类加载器加载到java虚拟机当中
4、.class文件记录着类的所有的信息

个人理解:

计算机通过加载到的.class文件已经知道类的所有信息了,但是为了让人也能知道这个类中描述的所有信息,所以才有了反射,就是将类的详细信息以对象的形式表达出来,方便人去进行手动管理。

就像汽车一样,原本我们使用汽车能开就可以了,但是难免有人想改装它,这时候就需要提供这个车子的架构图了。个人觉得之所以有反射,就是这个道理。

二、测试实例

(1)基础类

测试注解

package com.suncy.article.article10;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRefAnnotation {
}

测试基础类
两个构造方法,两个成员变量,两个成员方法

package com.suncy.article.article10;

import org.springframework.beans.factory.annotation.Value;

//添加测试注解
@MyRefAnnotation
public class MyRefTest {
    public int a;
    private String b;
    public MyRefTest() {
    }

    private MyRefTest(String b) {
        this.b = b;
    }

    public MyRefTest(int a) {
        this.a = a;
    }

    @Value("444")
    public void testA(String a) throws Exception{
        System.out.println("ttttt" + a);
    }

    private void testB() {
    }
}

(2) Class<?> 对象提供的一些方法

package com.suncy.article.article10;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

public class ReflexTestMain {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException,
            IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        //基本获取方法
        System.out.println("=====================获取Class<?>的三种方式=====================");
        MyRefTest myRefTest = new MyRefTest();
        Class<?> cls = myRefTest.getClass();
        System.out.println("myRefTest.getClass() : " + cls);

        Class<?> cls1 = MyRefTest.class;
        System.out.println("MyRefTest.class : " + cls1);

        Class<?> cls2 = Class.forName("com.suncy.article.article10.MyRefTest");
        System.out.println("Class.forName(xxx) : " + cls2);
        System.out.println();

        //基本使用方法
        //一、获取构造方法
        //1、获取所有的公有构造方法
        System.out.println("=======================获取Constructor<?>=========================");
        Constructor<?>[] constructors = cls.getConstructors();
        System.out.println("cls.getConstructors() : " + Arrays.toString(constructors));

        //2、获取所有构造方法 包括私有的 受保护的
        Constructor<?>[] constructors1 = cls.getDeclaredConstructors();
        System.out.println("cls.getDeclaredConstructors() : " + Arrays.toString(constructors1));

        //3、获取公有的无参构造方法
        Constructor<?> constructor = cls.getConstructor();
        System.out.println("cls.getConstructor() : " + constructor);

        //4、调用构造方法 生成对象
        System.out.println("通过constructor实例化对象");
        MyRefTest myRefTest1 = (MyRefTest) constructor.newInstance();
        System.out.println("myRefTest : " + myRefTest);
        System.out.println("myRefTest1 : " + myRefTest1);
        System.out.println();

        System.out.println("=======================获取Field=========================");
        //二、获取成员变量
        //1、获取所有的公有字段
        Field[] fields = cls.getFields();
        System.out.println("cls.getFields() : " + Arrays.toString(fields));

        //2、获取所有的字段
        Field[] fields1 = cls.getDeclaredFields();
        System.out.println("cls.getDeclaredFields() : " + Arrays.toString(fields1));

        //3、获取某个公有字段
        Field fieldA = cls.getField("a");
        System.out.println("cls.getField(xx) : " + fieldA);

        //4、获取某个字段,包含私有的
        Field fieldB = cls.getDeclaredField("b");
        System.out.println("cls.getDeclaredField(xx) : " + fieldB);
        System.out.println();

        System.out.println("======================获取Method=========================");
        //三、获取成员方法
        //1、获取所有公有的成员方法
        Method[] methods = cls.getMethods();
        System.out.println("cls.getMethods() : " + Arrays.toString(methods));

        //2、获取所有的成员方法 包含私有
        Method[] methods1 = cls.getDeclaredMethods();
        System.out.println("cls.getDeclaredMethods() : " + Arrays.toString(methods1));

        //3、获取某个公有字段
        Method methodA = cls.getMethod("testA", String.class);
        System.out.println("cls.getMethod(xx, String.class) : " + methodA);

        //4、获取某个字段,包含私有的
        Method methodB = cls.getDeclaredMethod("testB");
        System.out.println("cls.getDeclaredMethod(xx) : " + methodB);
        System.out.println();

        System.out.println("======================获取类上的Annotation==========================");

        //四、获取类注解
        //1、获取类上所有的注解
        Annotation[] annotations = cls.getAnnotations();
        System.out.println("cls.getAnnotations() : " + Arrays.toString(annotations));

        //2、获取类上特定的注解
        MyRefAnnotation annotation = cls.getAnnotation(MyRefAnnotation.class);
        System.out.println("cls.getAnnotation(xx) : " + annotation);

        //3、获取不存在的注解 会返回null
        Override annotation1 = cls.getAnnotation(Override.class);
        System.out.println("cls.getAnnotation(xx) : " + annotation1);
        System.out.println();

        //五、判断类的类型
        System.out.println("======================判断类的类型==========================");
        System.out.println("cls.isArray() : " + cls.isArray());                  //数组类
        System.out.println("cls.isAnnotation() : " + cls.isAnnotation());             //注解类
        System.out.println("cls.isAnnotationPresent(xx) : " + cls.isAnnotationPresent(MyRefAnnotation.class));        //特定注解类
        System.out.println("cls.isInterface() : " + cls.isInterface());               //接口类
        System.out.println("cls.isLocalClass() : " + cls.isLocalClass());              //局部类
        System.out.println("cls.isEnum() : " + cls.isEnum());                   //枚举类
        System.out.println("cls.isAnonymousClass() : " + cls.isAnonymousClass());         //匿名类
        System.out.println("cls.isMemberClass() : " + cls.isMemberClass());            //内部类
        System.out.println("cls.isInstance(xx) : " + cls.isInstance(myRefTest));      //判断对象是否是该类实例
        System.out.println();

        System.out.println("=======================Class<?>中的其他方法=========================");
        //六、其他方法
        //获取类加载器
        ClassLoader classLoader = cls.getClassLoader();
        System.out.println("cls.getClassLoader() : " + classLoader);

        Class<?>[] classes = cls.getClasses();
        System.out.println("cls.getClasses() : " + Arrays.toString(classes));

        Class<?>[] classes1 = cls.getDeclaredClasses();
        System.out.println("cls.getDeclaredClasses() : " + Arrays.toString(classes1));

        //获取类的名称(完整路径)
        String name = cls.getName();
        System.out.println("cls.getName() : " + name);

        //获取类的名称(类名称)
        String name1 = cls.getSimpleName();
        System.out.println("cls.getSimpleName() : " + name1);

        //获取类的名称(获取所传类从java语言规范定义的格式输出)
        String name2 = cls.getCanonicalName();
        System.out.println("cls.getCanonicalName() : " + name2);

        //获取父类类型
        Class<?> clsSuperclass = cls.getSuperclass();
        System.out.println("cls.getSuperclass() : " + clsSuperclass);

        //获取接口类型
        Class<?>[] clsSuperclass1 = cls.getInterfaces();
        System.out.println("cls.getInterfaces() : " + Arrays.toString(clsSuperclass1));

        //获取包名
        Package clsPackage = cls.getPackage();
        System.out.println("cls.getPackage() : " + clsPackage);
    }
}

响应结果

image.png

image.png

(3) Method、Field、Annotation提供的一些方法

package com.suncy.article.article10;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

public class ReflexTestMain1 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException,
            IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        Class<?> cls = Class.forName("com.suncy.article.article10.MyRefTest");

        //拿到Constructor对象
        Constructor<MyRefTest> constructor = (Constructor<MyRefTest>) cls.getConstructor();
        System.out.println("拿到MyRefTest类的Constructor对象 : " + constructor);

        //根据constructor实例化对象
        MyRefTest myRefTest = constructor.newInstance();
        System.out.println("根据这个myRefTest的constructor构造对象(constructor.newInstance()) : " + myRefTest);

        //拿到cls所有方法
        Method[] methods = cls.getMethods();
        System.out.println("拿到这个类所有公有成员方法(cls.getMethods()) : " + Arrays.toString(methods));
        System.out.println();

        //拿到cls特定的某个方法 执行myRefTest对象的这个特定的方法
        System.out.println("=============testA方法对应的Method对象================");
        Method methodTestA = cls.getMethod("testA", String.class);
        System.out.println("拿到testA方法的Method : " + methodTestA);

        // 调用对象方法
        System.out.println("调用testA方法 : ");
        methodTestA.invoke(myRefTest, "22312312");

        //拿到这个特定Method方法上的注解
        System.out.println("拿到methodA方法上的注解 : " + Arrays.toString(methodTestA.getDeclaredAnnotations()));
        //拿到这个特定Method方法上的异常
        System.out.println("拿到methodA方法上的异常 : " + Arrays.toString(methodTestA.getExceptionTypes()));
        System.out.println();

        //给myRefTest对象的a字段设置值 通过Field对象拿到这个a字段的值
        System.out.println("=============a字段对应的Field对象================");
        myRefTest.a = 34;
        Field fieldA = cls.getField("a");
        System.out.println("拿到a字段Field : " + fieldA);
        System.out.println("拿到字段a的值 : " + fieldA.getInt(myRefTest));

        System.out.println("是否能反射出a字段属性值 : " + fieldA.isAccessible());
        //设置是否能反射该属性数
        System.out.println("修改是否能反射a字段属性值 : fieldA.setAccessible(true)");
        fieldA.setAccessible(true);
        System.out.println("是否能反射出a字段属性值 : " + fieldA.isAccessible());
        System.out.println("是否是枚举类型的元素 : " + fieldA.isEnumConstant());
        System.out.println();

        //拿到cls类上持有的注解
        System.out.println("==========MyRefAnnotation注解对应的Annotation对象================");
        Annotation annotation = cls.getAnnotation(MyRefAnnotation.class);
        System.out.println("获取MyRefAnnotation注解的Annotation : " + annotation);

        //返回cls类的规范名称(获取所传类从java语言规范定义的格式输出)
        System.out.println("拿到类的规范名称 : " + cls.getCanonicalName());

        //返回注解的注解类型
        System.out.println("拿到注解的annotationType : " + annotation.annotationType());
        //返回注解的规范名称(获取所传类从java语言规范定义的格式输出)
        System.out.println("拿到注解的规范名称 : " + annotation.annotationType().getCanonicalName());
    }
}

响应结果

image.png

三、总结

1、反射相关类:Class、Constructor、Method、Field、Annotation。
2、代理常用的一种方式是: methodTestA.invoke(myRefTest, "22312312");
methodTestA表示一个特定的Method对象。myRefTest表示对象。22312312表示参数、参数数量需要去看Method指定方法的参数是多少。
3、多写demo测试一下,更为直观,印象更深。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Java反射 概述 Java反射机制可以让我们在编译期(Compile Time)之外的运行期(Runtime)检...
    Leocat阅读 1,126评论 0 0
  • 一、反射 通过Class实例获取 class 信息的方法称为反射(Reflection)。 (一) Class 类...
    瀑月流光阅读 799评论 0 0
  • java反射主要从以下几个方面理解 理解 Class 类 理解 Java 的类加载机制 学会使用 ClassLoa...
    境里婆娑阅读 11,567评论 0 11
  • Java 语言允许通过程序化的方式间接对 Class 进行操作, Class 文件由类装载器装载后,在 JVM 中...
    deniro阅读 1,342评论 0 40
  • 动态语言 动态语言,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化。比如...
    诺天高云淡阅读 349评论 1 0