Java反射

一、概述

反向探知,在程序运行过程中动态的获取类的相关属性

定义

动态获取类的内容以及动态调用对象的方法和获取属性的机制

优点

增加程序的灵活性,可以避免将固定的逻辑写死在程序中

可以提高程序的复用性

缺点

相比于直接调用,反射的效率要低得多

类的内部暴漏,带来安全隐患

反射慢的原因

  1. 调用了native方法
  2. 每次newInstance都会做安全检查 比较耗时
@CallerSensitive
public T newInstance()
    throws InstantiationException, IllegalAccessException
{
    if (System.getSecurityManager() != null) {
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
    }

    // NOTE: the following code may not be strictly correct under
    // the current Java memory model.

    // Constructor lookup
    if (cachedConstructor == null) {
        if (this == Class.class) {
            throw new IllegalAccessException(
                "Can not call newInstance() on the Class for java.lang.Class"
            );
        }
        try {
            Class<?>[] empty = {};
            final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
            // Disable accessibility checks on the constructor
            // since we have to do the security check here anyway
            // (the stack depth is wrong for the Constructor's
            // security check to work)
            java.security.AccessController.doPrivileged(
                new java.security.PrivilegedAction<Void>() {
                    public Void run() {
                            c.setAccessible(true);
                            return null;
                        }
                    });
            cachedConstructor = c;
        } catch (NoSuchMethodException e) {
            throw (InstantiationException)
                new InstantiationException(getName()).initCause(e);
        }
    }
    Constructor<T> tmpConstructor = cachedConstructor;
    // Security check (same as in java.lang.reflect.Constructor)
    int modifiers = tmpConstructor.getModifiers();
    if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
        Class<?> caller = Reflection.getCallerClass();
        if (newInstanceCallerCache != caller) {
            Reflection.ensureMemberAccess(caller, this, null, modifiers);
            newInstanceCallerCache = caller;
        }
    }
    // Run constructor
    try {
        return tmpConstructor.newInstance((Object[])null);
    } catch (InvocationTargetException e) {
        Unsafe.getUnsafe().throwException(e.getTargetException());
        // Not reached
        return null;
    }
}

使用反射和不使用反射对比

public class Main {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        long l1 = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            new Admin();
        }
        long l2 = System.currentTimeMillis();
        System.out.println("正常创建对象:" + (l2 - l1));

        long l3 = System.currentTimeMillis();
        Class<Admin> adminClass = Admin.class;
        for (int i = 0; i < 10000000; i++) {
            adminClass.newInstance();
        }
        long l4 = System.currentTimeMillis();
        System.out.println("反射创建对象:" + (l4 - l3));
    }
}

这里是创建10000000个对象,相差6.6倍,当创建对象的数量扩大为1000000000

在这里插入图片描述

可以看到正常创建仍然是5毫秒,而反射创建需要接近两秒。

可以发现,正常创建对象随着数量增加代价很小,而反射代价很大。原因就是前面提到的,每次创建都进行了检测。

二、基本操作

获取类对象

在这里插入图片描述

public class Main {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
        Class<Admin> adminClass1 = Admin.class;
        Class<?> adminClass2 = Class.forName("fs.Admin");
        Class<? extends Admin> adminClass3 = new Admin().getClass();
        Class<?> adminClass4 = Main.class.getClassLoader().loadClass("fs.Admin");
    }
}

这里演示的有四种方式

显示类的相关信息

public class Main {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
        Class<Admin> adminClass1 = Admin.class;
        Class<?> adminClass2 = Class.forName("fs.Admin");
        Class<? extends Admin> adminClass3 = new Admin().getClass();
        Class<?> adminClass4 = Main.class.getClassLoader().loadClass("fs.Admin");
        System.out.println(adminClass1.getModifiers());
        System.out.println(adminClass1.getPackage());
        System.out.println(adminClass1.getName());
        System.out.println(adminClass1.getSuperclass());
        System.out.println(adminClass1.getClassLoader());
        System.out.println(adminClass1.getSimpleName());
        System.out.println(adminClass1.getInterfaces());
        System.out.println(adminClass1.getAnnotations());
    }
}
1
package fs
fs.Admin
class java.lang.Object
sun.misc.Launcher$AppClassLoader@18b4aac2
Admin
[Ljava.lang.Class;@1b6d3586
[Ljava.lang.annotation.Annotation;@74a14482
  • adminClass1.getModifiers():获取修饰符
  • adminClass1.getPackage():获取包名
  • adminClass1.getName():获取全类名
  • adminClass1.getSuperclass():获取继承的类
  • adminClass1.getClassLoader():获取构造器
  • adminClass1.getSimpleName():获取类名
  • adminClass1.getInterfaces():获取实现的接口

获取到的修饰符解释

/**
     * The {@code int} value representing the {@code public}
     * modifier.
     */
    public static final int PUBLIC           = 0x00000001;

    /**
     * The {@code int} value representing the {@code private}
     * modifier.
     */
    public static final int PRIVATE          = 0x00000002;

    /**
     * The {@code int} value representing the {@code protected}
     * modifier.
     */
    public static final int PROTECTED        = 0x00000004;

    /**
     * The {@code int} value representing the {@code static}
     * modifier.
     */
    public static final int STATIC           = 0x00000008;

    /**
     * The {@code int} value representing the {@code final}
     * modifier.
     */
    public static final int FINAL            = 0x00000010;

    /**
     * The {@code int} value representing the {@code synchronized}
     * modifier.
     */
    public static final int SYNCHRONIZED     = 0x00000020;

    /**
     * The {@code int} value representing the {@code volatile}
     * modifier.
     */
    public static final int VOLATILE         = 0x00000040;

    /**
     * The {@code int} value representing the {@code transient}
     * modifier.
     */
    public static final int TRANSIENT        = 0x00000080;

    /**
     * The {@code int} value representing the {@code native}
     * modifier.
     */
    public static final int NATIVE           = 0x00000100;

    /**
     * The {@code int} value representing the {@code interface}
     * modifier.
     */
    public static final int INTERFACE        = 0x00000200;

    /**
     * The {@code int} value representing the {@code abstract}
     * modifier.
     */
    public static final int ABSTRACT         = 0x00000400;

    /**
     * The {@code int} value representing the {@code strictfp}
     * modifier.
     */
    public static final int STRICT           = 0x00000800;

    // Bits not (yet) exposed in the public API either because they
    // have different meanings for fields and methods and there is no
    // way to distinguish between the two in this class, or because
    // they are not Java programming language keywords
    static final int BRIDGE    = 0x00000040;
    static final int VARARGS   = 0x00000080;
    static final int SYNTHETIC = 0x00001000;
    static final int ANNOTATION  = 0x00002000;
    static final int ENUM      = 0x00004000;
    static final int MANDATED  = 0x00008000;

这里可以看到,public为1,private为2…对于各类修饰符及关键字,这里都有相关常量的定义。

上面显示为1,显然是public修饰符

  • 这里继续尝试,对类加上抽象
1025

输出结果变为了2015,查上面的数据,可以发现ABSTRACT= 0x00000400即1024,然后前面给的还有public,所以总和为1025.

由于可以推出,我们拿到任意的修饰符数字,都可以推出修饰符

类中的方法操作

public class Main {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
        Class<Admin> adminClass1 = Admin.class;
        Admin admin = adminClass1.newInstance();
        //获取当前类及父类中所有的共有的方法
        Method[] methods = adminClass1.getMethods();
        for (Method method : methods) {
            System.out.println(method.getModifiers() + " " + method.getName());
        }
        System.out.println("--------------");
        //获取本类中的所有方法
        Method[] methods1 = adminClass1.getDeclaredMethods();
        for (Method method : methods1) {
            System.out.println(method.getModifiers() + " " + method.getName());
        }
        Method read = adminClass1.getDeclaredMethod("read");
        //放开私用方法的调用
        read.setAccessible(true);
        read.invoke(admin);
        //传参的方法调用
        Method saying = adminClass1.getDeclaredMethod("saying", String.class);
        saying.invoke(admin,"哈哈哈");
    }
}
1 saying
1 getAge
1 setAge
1 getAdminName
1 setGrade
1 getGrade
1 study
1 setAdminName
17 wait
273 wait
17 wait
1 equals
1 toString
257 hashCode
273 getClass
273 notify
273 notifyAll
--------------
2 read
1 saying
1 getAge
1 setAge
1 getAdminName
1 setGrade
1 getGrade
1 study
1 setAdminName
admin reading
admin哈哈哈

构造器的操作

public class Main {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
        Class<Admin> adminClass1 = Admin.class;
        //获取所有公共的构造器
        Constructor<?>[] constructors = adminClass1.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor.getModifiers() + " " + constructor);
        }
        System.out.println("-------------------");
        Constructor<?>[] constructors1 = adminClass1.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors1) {
            System.out.println(constructor.getModifiers() + " " + constructor.getName());
        }
        //直接通过newInstance创建对象
        Admin admin = adminClass1.newInstance();
        //获取对应的构造器创建对象
        Constructor<Admin> declaredConstructor = adminClass1.getDeclaredConstructor();
        Admin admin1 = declaredConstructor.newInstance();
        //私有构造器调用需要先开放方法的权限
        declaredConstructor.setAccessible(true);
        Admin admin2 = declaredConstructor.newInstance();
    }
}
1 public fs.Admin()
-------------------
1 fs.Admin

联想单例模式

常见的一种单例模式

将构造器私有,然后提供一个获得对象的方法

private static Admin admin = null;


private Admin(){}

public Admin getAdmin() {
    if (admin == null){
        admin = new Admin();
    }
    return admin;
}

可以发现,如果我们通过反射,会获得这个私有构造器的权限,从而创建对象,破坏单例。

解决方法

我们可以在私有构造器上,增加一个异常处理

private Admin(){
    if (Admin.admin != null){
        throw new RuntimeException("实例已经创建,不允许再创建了!");
    }
}
public class Main {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
        Class<Admin> adminClass1 = Admin.class;
        Constructor<Admin> declaredConstructor = adminClass1.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);
        Admin admin1 = Admin.getAdmin();
        Admin admin = declaredConstructor.newInstance();
        admin.setAdminName("aaa");
    }
}
Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at fs.Main.main(Main.java:21)
Caused by: java.lang.RuntimeException: 实例已经创建,不允许再创建了!
	at fs.Admin.<init>(Admin.java:22)
	... 5 more

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

capkin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值