首页后端开发其他后端知识Java中的反射的定义功能及使用是怎样的

Java中的反射的定义功能及使用是怎样的

时间2024-03-27 11:18:03发布访客分类其他后端知识浏览336
导读:今天就跟大家聊聊有关“Java中的反射的定义功能及使用是怎样的”的内容,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。 java基础栏目今天介绍超详细的JVM反射原理...
今天就跟大家聊聊有关“Java中的反射的定义功能及使用是怎样的”的内容,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。



java基础栏目今天介绍超详细的JVM反射原理技术点总结哦。

反射定义

1,JAVA反射机制是在运行状态中

对于任意一个类,都能够知道这个类的所有属性和方法;

对于任意一个对象,都能够调用它的任意一个方法和属性;

这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

反射提供的功能:

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时调用任意一个对象的方法

(如果属性是private,正常情况下是不允许外界操作属性值,这里可以用Field类的setAccessible(true)方法,暂时打开操作的权限)

反射的使用场景

  • Java编码时知道类和对象的具体信息,此时直接对类和对象进行操作即可,无需反射
  • 如果编码时不知道类或者对象的具体信息,此时应该使用反射来实现

反射源码解析

举例API :

Class.forName("com.my.reflectTest").newInstance()复制代码

1. 反射获取类实例 Class.forName("xxx");

  首先调用了 java.lang.Class 的静态方法,获取类信息!

注意:forName()反射获取类信息,并没有将实现留给了java,而是交给了jvm去加载!

主要是先获取 ClassLoader, 然后调用 native 方法,获取信息,加载类则是回调 入参ClassLoader 进类加载!

 @CallerSensitive
    public static Class?>
 forName(String className)
                throws ClassNotFoundException {
    
        // 先通过反射,获取调用进来的类信息,从而获取当前的 classLoader
        Class?>
     caller = Reflection.getCallerClass();
    
        // 调用native方法进行获取class信息
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);

    }
    复制代码

2. java.lang.ClassLoader-----loadClass()

// java.lang.ClassLoader
    protected Class?>
 loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {

        // 先获取锁
        synchronized (getClassLoadingLock(name)) {
    
            // First, check if the class has already been loaded
            // 如果已经加载了的话,就不用再加载了
            Class?>
     c = findLoadedClass(name);

            if (c == null) {
    
                long t0 = System.nanoTime();

                try {

                    // 双亲委托加载
                    if (parent != null) {
    
                        c = parent.loadClass(name, false);

                    }
 else {
    
                        c = findBootstrapClassOrNull(name);

                    }

                }
 catch (ClassNotFoundException e) {

                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

 
                // 父类没有加载到时,再自己加载
                if (c == null) {
    
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
    
                    c = findClass(name);
    
 
                    // this is the defining class loader;
     record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
    
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
    
                    sun.misc.PerfCounter.getFindClasses().increment();

                }

            }

            if (resolve) {
    
                resolveClass(c);

            }
    
            return c;

        }

    }

    
    protected Object getClassLoadingLock(String className) {
    
        Object lock = this;

        if (parallelLockMap != null) {
    
            // 使用 ConcurrentHashMap来保存锁
            Object newLock = new Object();
    
            lock = parallelLockMap.putIfAbsent(className, newLock);

            if (lock == null) {
    
                lock = newLock;

            }

        }
    
        return lock;

    }
    
    
    protected final Class?>
 findLoadedClass(String name) {
    
        if (!checkName(name))
            return null;
    
        return findLoadedClass0(name);

    }
复制代码

3. newInstance()

newInstance() 其实相当于调用类的无参构造函数,主要做了三件事复制代码
  • 权限检测,如果不通过直接抛出异常;

  • 查找无参构造器,并将其缓存起来;

  • 调用具体方法的无参构造方法,生成实例并返回;

// 首先肯定是 Class.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
        // newInstance() 其实相当于调用类的无参构造函数,所以,首先要找到其无参构造器
        if (cachedConstructor == null) {

            if (this == Class.class) {
    
                // 不允许调用 Class 的 newInstance() 方法
                throw new IllegalAccessException(
                    "Can not call newInstance() on the Class for java.lang.Class"
                );

            }

            try {
    
                // 获取无参构造器
                Class?>
[] empty = {
}
    ;
    
                final ConstructorT>
     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.PrivilegedActionVoid>
() {

                        public Void run() {
    
                                c.setAccessible(true);
    
                                return null;

                            }

                        }
    );
    
                cachedConstructor = c;

            }
 catch (NoSuchMethodException e) {
    
                throw (InstantiationException)
                    new InstantiationException(getName()).initCause(e);

            }

        }
    
        ConstructorT>
     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;

        }

    }
    复制代码

4. getConstructor0() 为获取匹配的构造方器;分三步:

  1. 先获取所有的constructors, 然后通过进行参数类型比较;   2. 找到匹配后,通过 ReflectionFactory copy一份constructor返回;   3. 否则抛出 NoSuchMethodException;

private ConstructorT>
     getConstructor0(Class?>
[] parameterTypes,
                                        int which) throws NoSuchMethodException
    {
    
        // 获取所有构造器
        ConstructorT>
    [] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
    
        for (ConstructorT>
 constructor : constructors) {

            if (arrayContentsEq(parameterTypes,
                                constructor.getParameterTypes())) {
    
                return getReflectionFactory().copyConstructor(constructor);

            }

        }
    
        throw new NoSuchMethodException(getName() + ".init>
    " + argumentTypesToString(parameterTypes));

    }
    复制代码

5. privateGetDeclaredConstructors(), 获取所有的构造器主要步骤;

  1. 先尝试从缓存中获取;   2. 如果缓存没有,则从jvm中重新获取,并存入缓存,缓存使用软引用进行保存,保证内存可用;

// 获取当前类所有的构造方法,通过jvm或者缓存
    // Returns an array of "root" constructors. These Constructor
    // objects must NOT be propagated to the outside world, but must
    // instead be copied via ReflectionFactory.copyConstructor.
    private ConstructorT>
[] privateGetDeclaredConstructors(boolean publicOnly) {
    
        checkInitted();
    
        ConstructorT>
    [] res;
    
        // 调用 reflectionData(), 获取保存的信息,使用软引用保存,从而使内存不够可以回收
        ReflectionDataT>
     rd = reflectionData();

        if (rd != null) {
    
            res = publicOnly ? rd.publicConstructors : rd.declaredConstructors;
    
            // 存在缓存,则直接返回
            if (res != null) return res;

        }
    
        // No cached value available;
 request value from VM
        if (isInterface()) {
    
            @SuppressWarnings("unchecked")
            ConstructorT>
    [] temporaryRes = (ConstructorT>
    []) new Constructor?>
    [0];
    
            res = temporaryRes;

        }
 else {
    
            // 使用native方法从jvm获取构造器
            res = getDeclaredConstructors0(publicOnly);

        }

        if (rd != null) {

            // 最后,将从jvm中读取的内容,存入缓存
            if (publicOnly) {
    
                rd.publicConstructors = res;

            }
 else {
    
                rd.declaredConstructors = res;

            }

        }
    
        return res;

    }
    
    
    // Lazily create and cache ReflectionData
    private ReflectionDataT>
 reflectionData() {
    
        SoftReferenceReflectionDataT>
    >
     reflectionData = this.reflectionData;
    
        int classRedefinedCount = this.classRedefinedCount;
    
        ReflectionDataT>
     rd;
    
        if (useCaches &
    &
    
            reflectionData != null &
    &
    
            (rd = reflectionData.get()) != null &
    &

            rd.redefinedCount == classRedefinedCount) {
    
            return rd;

        }
    
        // else no SoftReference or cleared SoftReference or stale ReflectionData
        // ->
     create and replace new instance
        return newReflectionData(reflectionData, classRedefinedCount);

    }
    
    
    // 新创建缓存,保存反射信息
    private ReflectionDataT>
     newReflectionData(SoftReferenceReflectionDataT>
    >
 oldReflectionData,
                                                int classRedefinedCount) {
    
        if (!useCaches) return null;

 
        // 使用cas保证更新的线程安全性,所以反射是保证线程安全的
        while (true) {
    
            ReflectionDataT>
     rd = new ReflectionData>
    (classRedefinedCount);
    
            // try to CAS it...
            if (Atomic.casReflectionData(this, oldReflectionData, new SoftReference>
(rd))) {
    
                return rd;

            }
    
            // 先使用CAS更新,如果更新成功,则立即返回,否则测查当前已被其他线程更新的情况,如果和自己想要更新的状态一致,则也算是成功了
            oldReflectionData = this.reflectionData;
    
            classRedefinedCount = this.classRedefinedCount;
    
            if (oldReflectionData != null &
    &
    
                (rd = oldReflectionData.get()) != null &
    &

                rd.redefinedCount == classRedefinedCount) {
    
                return rd;

            }

        }

    }
    复制代码

另外,使用 relactionData() 进行缓存保存;ReflectionData 的数据结构如下!

// reflection data that might get invalidated when JVM TI RedefineClasses() is called
    private static class ReflectionDataT>
 {
    
        volatile Field[] declaredFields;
    
        volatile Field[] publicFields;
    
        volatile Method[] declaredMethods;
    
        volatile Method[] publicMethods;
    
        volatile ConstructorT>
    [] declaredConstructors;
    
        volatile ConstructorT>
    [] publicConstructors;
    
        // Intermediate results for getFields and getMethods
        volatile Field[] declaredPublicFields;
    
        volatile Method[] declaredPublicMethods;
    
        volatile Class?>
    [] interfaces;
    
 
        // Value of classRedefinedCount when we created this ReflectionData instance
        final int redefinedCount;

 
        ReflectionData(int redefinedCount) {
    
            this.redefinedCount = redefinedCount;

        }

    }
    复制代码

6.通过上面,获取到 Constructor 了!接下来就只需调用其相应构造器的 newInstance(),即返回实例了!

// return tmpConstructor.newInstance((Object[])null);
 
    // java.lang.reflect.Constructor
    @CallerSensitive
    public T newInstance(Object ... initargs)
        throws InstantiationException, IllegalAccessException,
               IllegalArgumentException, InvocationTargetException
    {

        if (!override) {

            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
    
                Class?>
     caller = Reflection.getCallerClass();
    
                checkAccess(caller, clazz, null, modifiers);

            }

        }
    
        if ((clazz.getModifiers() &
     Modifier.ENUM) != 0)
            throw new IllegalArgumentException("Cannot reflectively create enum objects");
    
        ConstructorAccessor ca = constructorAccessor;
   // read volatile
        if (ca == null) {
    
            ca = acquireConstructorAccessor();

        }
    
        @SuppressWarnings("unchecked")
        T inst = (T) ca.newInstance(initargs);
    
        return inst;

    }

    // sun.reflect.DelegatingConstructorAccessorImpl
    public Object newInstance(Object[] args)
      throws InstantiationException,
             IllegalArgumentException,
             InvocationTargetException
    {
    
        return delegate.newInstance(args);

    }

    // sun.reflect.NativeConstructorAccessorImpl
    public Object newInstance(Object[] args)
        throws InstantiationException,
               IllegalArgumentException,
               InvocationTargetException
    {
    
        // We can't inflate a constructor belonging to a vm-anonymous class
        // because that kind of class can't be referred to by name, hence can't
        // be found from the generated bytecode.
        if (++numInvocations >
     ReflectionFactory.inflationThreshold()
                &
    &
 !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {
    
            ConstructorAccessorImpl acc = (ConstructorAccessorImpl)
                new MethodAccessorGenerator().
                    generateConstructor(c.getDeclaringClass(),
                                        c.getParameterTypes(),
                                        c.getExceptionTypes(),
                                        c.getModifiers());
    
            parent.setDelegate(acc);

        }
    
 
        // 调用native方法,进行调用 constructor
        return newInstance0(c, args);

    }
    复制代码

返回构造器的实例后,可以根据外部进行进行类型转换,从而使用接口或方法进行调用实例功能了。


以上就是关于“Java中的反射的定义功能及使用是怎样的”的相关知识,感谢各位的阅读,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注网络,小编每天都会为大家更新不同的知识。

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!


若转载请注明出处: Java中的反射的定义功能及使用是怎样的
本文地址: https://pptw.com/jishu/654184.html
在JavaScript字符串中常见的基础方法有哪些 node中path路径模块用来处理什么问题,用法是什么

游客 回复需填写必要信息