初探反射机制

如果需要修改Test类对象的private testName属性,我们会怎么做呢?

class Test {
    private String testName = "hello";

    public void setTestName(String name) {
        testName = name;
    }
}

通常我们可以提供一个public setTestName方法去修改testName值。
当然,还可以使用本文的主角\color{red}{反射机制}达到修改testName值。

反射机制常用方法之一:修改对象中private属性
创建Test类对象test,test对象中有私有属性testName,testName初始值为hello。通过反射,将testName值修改成world。

class Test {
    private String testName = "hello";

    public String getTestName() {
        return testName;
    }

    public static void main(String[] args) {
        try {
            Test test = new Test();
            System.out.println("testName:" + test.getTestName());//testName:hello
            Class<?> clazz = test.getClass();
            Field testNameField = clazz.getDeclaredField("testName");
            testNameField.setAccessible(true);
            testNameField.set(test, "world");
            System.out.println("testName:" + test.getTestName());//testName:world
        } catch (Exception e) {
        }
    }
}

通过例子我们感受到反射机制的作用,到底什么是反射,为什么需要反射,反射常用方法还有哪些。

  • 什么是反射?

在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。
用比喻来说,反射就是程序在运行的时候能够“观察”并且“修改”自己的行为。

在Java中,
反射能“观察”自己的具体表现就是:对于任意一个类,都能够知道这个类的所有方法和属性。
反射能“修改”自己的具体表现就是:对于任意一个对象,都能够调用它的所有方法和改变所有的属性。

  • 为什么需要反射?

1.反射使得设计更优雅易懂,例如日常使用的Spring框架,注解的形式就相当优雅易懂而且实用。
关于“注解”详细介绍请点击//TODO

@Controller
class Test {
    public static void main(String[] args) {
        Class clazz = Test.class;
        Annotation[] annotations = clazz.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
    }
}

2.Java中的动态代理、拦截器等,都是使用反射的“观察”和“修改”能力。

通过反射的“观察”和“修改”能力,可以设计出更优雅易读而且实用的应用程序。为什么需要反射?因为在设计程序时,需要“观察”和“修改”的能力,而拥有这些能力的我们定义为反射。

  • 反射的常用方法

获取Class对象的三种方式

1.通过对象获取

class Test {
    public static void main(String[] args) {
        Test test = new Test();
        Class clazz = test.getClass();
    }
}

2.通过类获取

class Test {
    public static void main(String[] args) {
        Class clazz = Test.class;
    }
}

3.通过Class.forName获取

class Test {
    public static void main(String[] args) {
        try {
            Class clazz = Class.forName("Test");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
获取类字段
class Test {
    private String nickname;

    public static void main(String[] args) {
        Class clazz = Test.class;
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
    }
}
获取类方法
class Test {
    private String nickname;

    public String getNickname() {
        return nickname;
    }

    public static void main(String[] args) {
        Class clazz = Test.class;
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
    }
}
获取类构造器
class Test {
    private String nickname;

    public Test(String nickname) {
        this.nickname = nickname;
    }

    public static void main(String[] args) {
        try {
            Class clazz = Test.class;
            Constructor constructor = clazz.getConstructor(String.class);
            Test test = (Test) constructor.newInstance("tom");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

更多反射的方法可以查看Class类的源码。查看源码时,例如Class.forName,里面调用forName0方法,会发现forName0方法是一个native方法,如何查看native方法的源码,JDK native源码查看

    @CallerSensitive
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        Class<?> caller = Reflection.getCallerClass();
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }

    /** Called after security check for system loader access checks have been made. */
    private static native Class<?> forName0(String name, boolean initialize,
                                            ClassLoader loader,
                                            Class<?> caller)
        throws ClassNotFoundException;

我们会发现,Java中,反射基本围绕着Class类展开,去实现反射的“观察”和“修改”能力,关于Class类文件的结构,参考Class类文件的结构。了解Class类文件的结构后,需要再去了解虚拟机类加载机制以及类加载器//TODO。
而本文主要介绍反射机制基础概念,反射的意义及反射常用方法。
想深入理解反射在JVM中的实现原理,除了需要阅读源码(包括阅读native方法源码),还需要理解Class类文件的结构,以及虚拟机类加载机制,做完这些工作,才算比较明白反射机制。

深入理解反射机制//TODO

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