Java 深入学习(27) —— 反射:运行时的类型信息

1 什么是反射


反射(Reflection) 是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取类的信息,并且可以操作类或对象的内部属性

通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。

反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。


2 反射的功能


1.在运行时判断任意一个对象所属的类;
2.在运行时构造任意一个类的对象;
3.在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
4.在运行时调用任意一个对象的方法

重点:是运行时而不是编译时


3 反射的工作原理


当我们编写完一个Java项目之后,每个java文件都会被编译成一个.class文件。

这些Class对象承载了这个类的所有信息,包括父类、接口、构造函数、方法、属性等。

这些class文件在程序运行时会被ClassLoader加载到虚拟机中。

当一个类被加载以后,Java虚拟机就会在内存中自动产生一个Class对象。

我们通过new的形式创建对象实际上就是通过这些Class来创建,只是这个过程对于我们是不透明的而已。

反射的工作原理就是借助Class 、Constructor 、Method 、Field 这四个类在程序运行时动态访问和修改任何类的行为和状态。


4 反射的简单应用


package com.test.class_obj;

import java.lang.reflect.*;
import java.util.regex.*;

public class ShowMethods {
    private static String usage =
            "usage:\n" +
                    "ShowMethods qualified.class.name\n" +
                    "To show all methods in class or:\n" +
                    "ShowMethods qualified.class.name word\n" +
                    "To search for methods involving 'word'";
    private static Pattern p = Pattern.compile("\\w+\\.");
    public static void main(String[] args) {
        if(args.length < 1) {
            System.out.println(usage);
            System.exit(0);
        }
        int lines = 0;
        try {
            // 通过类的完全限定名,查找并加载 Class 对象
            Class<?> c = Class.forName(args[0]);
            Method[] methods = c.getMethods();
            Constructor[] ctors = c.getConstructors();
            if(args.length == 1) {
                for(Method method : methods)
                    System.out.println(
                            p.matcher(method.toString()).replaceAll(""));
                System.out.println("-----------------------------");
                for(Constructor ctor : ctors)
                    System.out.println(p.matcher(ctor.toString()).replaceAll(""));
                lines = methods.length + ctors.length;
            } else {
                for(Method method : methods)
                    if(method.toString().indexOf(args[1]) != -1) {
                        System.out.println(
                                p.matcher(method.toString()).replaceAll(""));
                        lines++;
                    }
                for(Constructor ctor : ctors)
                    if(ctor.toString().indexOf(args[1]) != -1) {
                        System.out.println(p.matcher(
                                ctor.toString()).replaceAll(""));
                        lines++;
                    }
            }
        } catch(ClassNotFoundException e) {
            System.out.println("No such class: " + e);
        }
    }
}

这里写图片描述


5 反射性能较差的原因

Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.

由于反射涉及类型的动态解析,所以无法执行某些Java虚拟机优化。 因此,反射操作比非反射操作具有更慢的性能,应该避免在性能敏感的应用程序中频繁调用的代码段。


6 参考资料

1、深入解析Java反射(1) - 基础
http://www.sczyh30.com/posts/Java/java-reflection-1/#%E4%B8%80%E3%80%81%E5%9B%9E%E9%A1%BE%EF%BC%9A%E4%BB%80%E4%B9%88%E6%98%AF%E5%8F%8D%E5%B0%84%EF%BC%9F

2、学习java应该如何理解反射?
https://www.zhihu.com/question/24304289

3、深入浅出反射
https://zhuanlan.zhihu.com/p/21423208

4、Java Reflection Performance
https://stackoverflow.com/questions/435553/java-reflection-performance


7 反射中的骚操作


通过反射可以无视 诸如 private 之类的访问修饰符

今天在看 http://stamen.iteye.com/blog/1497981 的时候,看到里边说 甚至连 void 都有 对应的 class 对象。

于是突发奇想的尝试了一下

这是 Void.java 的源码

package java.lang;

/**
 * The {@code Void} class is an uninstantiable placeholder class to hold a
 * reference to the {@code Class} object representing the Java keyword
 * void.
 *
 * @author  unascribed
 * @since   JDK1.1
 */
public final
class Void {

    /**
     * The {@code Class} object representing the pseudo-type corresponding to
     * the keyword {@code void}.
     */
    @SuppressWarnings("unchecked")
    public static final Class<Void> TYPE = (Class<Void>) Class.getPrimitiveClass("void");

    /*
     * The Void class cannot be instantiated.
     */
    private Void() {}
}

可以看到 Void 的构造器是私有的。

但是,通过如下的方式就可以使用 Void 私有的构造器啦~~~~

        Constructor constructor = Void.class.getConstructor();
        constructor.setAccessible(true);
        Void void_b = (Void) constructor.newInstance();
        System.out.println("------------");
        System.out.println(void_b);
        System.out.println("------------");

这里写图片描述

学习Spring必学的Java基础知识(1)—-反射
http://stamen.iteye.com/blog/1497981


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值