• Java注解@PostConstruct使用及相关原理分析


    @PostConstruct很多人都不会陌生,很多人都会用PostConstruct来进行一些初始化相关的操作,被PostConstruct标注的方法会在对应的Bean完成依赖注入之后执行,所以并不是Spring容器刷新完成后才执行,那么PostConstruct注解到底怎么生效的?接着往下说。

    先看个实际的简单的例子,并试着回答一下从Bean实例化开始分别都经历了哪些过程。

    @Slf4j
    @Component
    public class TestPost {
    
        @Autowired
        private TestDemo testDemo;
    
    
        @PostConstruct
        public void testA(String args){
            try {
                Thread.sleep(3000);
            }catch (Exception ignore){
            }
            testDemo = new TestDemo();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • Spring容器首先要将TestDemo给注入进来,如果当前容器内没有TestDemo,那就先去把TestDemo给注册到容器里
    • 然后相关的依赖都注入完成了,开始执行被PostConstruct标注着的testA。
    • 先休眠个3秒,然后新创建一个TestDemo的实例并指向成员变量testDemo。

    然而其实会发生的就是根本执行不到testA的内容就报错了

    Lifecycle method annotation requires a no-arg method: public void com.demo.demo.service.TestPost.testA(java.lang.String)
    
    • 1

    你扣了扣脑门,这是为什么啊?你管我有没有入参呢?你Spring又是啥时候偷偷检查的?这个放在后面来讲,我们再进入一个代码并试着分析一下输出顺序。再扩展一下,假如父类也有初始化方法,那么先子类还是先父类的呢?

    @Slf4j
    @Component
    public class TestPost {
    
    
        @PostConstruct
        public void testC(){
            log.info("method C run! ");
        }
    
        @PostConstruct
        public void testA(){
            log.info("method A run!");
        }
    
        @PostConstruct
        public void testB(){
            log.info("method B run!");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    接下来就一步一步顺着揭开面纱

    看着朴实无华的标准注解写法。

    @Documented
    @Retention (RUNTIME)
    @Target(METHOD)
    public @interface PostConstruct {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    你试着看了看哪里用到了这个注解,好家伙,原来就是CommonAnnotationBeanPostProcessor你这个后置处理器用到了啊。

    public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
            implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
    
        public CommonAnnotationBeanPostProcessor() {
            setOrder(Ordered.LOWEST_PRECEDENCE - 3);
            //真是熟悉的身影
            setInitAnnotationType(PostConstruct.class);
            //猜都猜的到这个小伙子会在这里
            setDestroyAnnotationType(PreDestroy.class);
            ignoreResourceType("javax.xml.ws.WebServiceContext");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    setInitAnnotationType是父类InitDestroyAnnotationBeanPostProcessor的方法之一,主要是就是指定配置bean之后的初始化注解类型。

    public class InitDestroyAnnotationBeanPostProcessor  {
    
        //这里就给你设定一下,传入的就是PostConstruct
        public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
            this.initAnnotationType = initAnnotationType;
        }
    
        //这里就是用到的地方,clazz是我们对应的bean
        private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
            if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
                return this.emptyLifecycleMetadata;
            }
    
            //初始化方法集合
            List<LifecycleElement> initMethods = new ArrayList<>();
            //销毁方法集合
            List<LifecycleElement> destroyMethods = new ArrayList<>();
            //targetClass需要处理的Class
            Class<?> targetClass = clazz;
            do {
                final List<LifecycleElement> currInitMethods = new ArrayList<>();
                final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
    
                ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                    //看看是不是被initAnnotationType也就是我们的PostConstruct注解标注了
                    if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
                        //生成LifecycleElement并加到初始化方法列表里,这里就是不然你加方法入参的地方,后面说
                        LifecycleElement element = new LifecycleElement(method);
                        currInitMethods.add(element);
                        if (logger.isTraceEnabled()) {
                            logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
                        }
                    }
                    if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
                        currDestroyMethods.add(new LifecycleElement(method));
                        if (logger.isTraceEnabled()) {
                            logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
                        }
                    }
                });
                //由于是从此类往父类开找,这个我们一眼就看出来父类的先执行了
                initMethods.addAll(0, currInitMethods);
                //不言而喻
                destroyMethods.addAll(currDestroyMethods);
                //指向父类
                targetClass = targetClass.getSuperclass();
            }
            //也就是往父类挨个找,直到父类为空或者就是Object类
            while (targetClass != null && targetClass != Object.class);
    
            return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
                    new LifecycleMetadata(clazz, initMethods, destroyMethods));
        }
      
        //就是它做的事儿
        public LifecycleElement(Method method) {
            //你这方法入参要是不为0,直接就是一手报错,没问题吧
            if (method.getParameterCount() != 0) {
                throw new IllegalStateException("Lifecycle method annotation requires a no-arg method: " + method);
            }
            this.method = method;
            this.identifier = (Modifier.isPrivate(method.getModifiers()) ?
                    ClassUtils.getQualifiedMethodName(method) : method.getName());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    bean的后置处理器什么时候被调用,自己怎么自定义bean后置处理器这个留在以后再说。

    回到开始的问题,一个类中多个PostConstruct执行顺序又怎么说?首先就是我们自己如果跑一下代码应该可以很快得知内容。

    第一次的运行结果: A -> B -> C,真相那都就是name的排序结果?

    com.demo.demo.service.TestPost           : method A run!
    com.demo.demo.service.TestPost           : method B run!
    com.demo.demo.service.TestPost           : method C run! 
    
    • 1
    • 2
    • 3

    第二次的运行结果:C -> B -> A,这结果真是很量子力学,因为感受到我们的观测,所以第二次程序就按照相反的顺序执行。

    com.demo.demo.service.TestPost           : method C run! 
    com.demo.demo.service.TestPost           : method B run!
    com.demo.demo.service.TestPost           : method A run!
    
    • 1
    • 2
    • 3

    第三次的运行结果:B -> C -> A,打扰了,搁这儿玩全排序呢?

    com.demo.demo.service.TestPost           : method B run!
    com.demo.demo.service.TestPost           : method C run! 
    com.demo.demo.service.TestPost           : method A run!
    
    • 1
    • 2
    • 3

    三次都是亲手跑的,不是我自己脑补写上去的,实际上这玩意就是随机的,也就是顺序不固定。那问题来了,为什么不固定?Spring写了个随机函数?允许我加粗个标题。

    多个@PostConstruct标注方法顺序为什么是随机的?

    回到我们上面的InitDestroyAnnotationBeanPostProcessor后置处理器的buildLifecycleMetadata方法,我再贴一次

    public class InitDestroyAnnotationBeanPostProcessor  {
      
        private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
            if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
                return this.emptyLifecycleMetadata;
            }
            List<LifecycleElement> initMethods = new ArrayList<>();
            List<LifecycleElement> destroyMethods = new ArrayList<>();
            Class<?> targetClass = clazz;
            do {
                final List<LifecycleElement> currInitMethods = new ArrayList<>();
                final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
    
                //其实重要的就是这个,调用了ReflectionUtils的doWithLocalMethods
                //doWithLocalMethods的两个入参:一个目标类一个函数式接口MethodCallback并在这层写了doWith实现
                ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                    if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
                        LifecycleElement element = new LifecycleElement(method);
                        //这个currInitMethods是个list,所以添加顺序就是固定的,那么底层的遍历顺序才是决定方法顺序的地方
                        //所以需要到ReflectionUtils.doWithLocalMethods去查看原因
                        currInitMethods.add(element);
                        if (logger.isTraceEnabled()) {
                            logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
                        }
                    }
                    if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
                        currDestroyMethods.add(new LifecycleElement(method));
                        if (logger.isTraceEnabled()) {
                            logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
                        }
                    }
                });
                initMethods.addAll(0, currInitMethods);
                destroyMethods.addAll(currDestroyMethods);
                targetClass = targetClass.getSuperclass();
            }
            while (targetClass != null && targetClass != Object.class);
    
            return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
                    new LifecycleMetadata(clazz, initMethods, destroyMethods));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    嗖的一下啊,我们就来到了ReflectionUtils.doWithLocalMethods这里

    public abstract class ReflectionUtils {
        public static void doWithLocalMethods(Class<?> clazz, MethodCallback mc) {
            //下面是对methods的遍历,所以methods数组的顺序就决定了后面执行的顺序
            Method[] methods = getDeclaredMethods(clazz, false);
            for (Method method : methods) {
                try {
                    mc.doWith(method);
                }
                catch (IllegalAccessException ex) {
                    throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
                }
            }
        }
    
        private static Method[] getDeclaredMethods(Class<?> clazz, boolean defensive) {
            Assert.notNull(clazz, "Class must not be null");
            //这里有个declaredMethodsCache,正常的缓存设计,那我们肯定看没有缓存从源头拿的时候了
            Method[] result = declaredMethodsCache.get(clazz);
            if (result == null) {
                try {
                    //这里就是核心了,这里就跳到Class类去了,想来也是肯定的,毕竟要获取类的信息
                    Method[] declaredMethods = clazz.getDeclaredMethods();
                    //这个是找接口层默认实现的方法,甭管它
                    List<Method> defaultMethods = findConcreteMethodsOnInterfaces(clazz);
                    if (defaultMethods != null) {
                        result = new Method[declaredMethods.length + defaultMethods.size()];
                        System.arraycopy(declaredMethods, 0, result, 0, declaredMethods.length);
                        int index = declaredMethods.length;
                        for (Method defaultMethod : defaultMethods) {
                            result[index] = defaultMethod;
                            index++;
                        }
                    }
                    else {
                        result = declaredMethods;
                    }
                    declaredMethodsCache.put(clazz, (result.length == 0 ? EMPTY_METHOD_ARRAY : result));
                }
                catch (Throwable ex) {
                    throw new IllegalStateException("Failed to introspect Class [" + clazz.getName() +
                            "] from ClassLoader [" + clazz.getClassLoader() + "]", ex);
                }
            }
            return (result.length == 0 || !defensive) ? result : result.clone();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    让我们来到JAVA领域的核心类,Class类

    public final class Class<T> implements java.io.Serializable, GenericDeclaration, Type, AnnotatedElement {
      
        @CallerSensitive
        public Method[] getDeclaredMethods() throws SecurityException {
            //检查行为
            checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
            //好了,就是privateGetDeclaredMethods方法来的,快要接近终点了,马上就要真相大白了
            return copyMethods(privateGetDeclaredMethods(false));
        }
    
        private Method[] privateGetDeclaredMethods(boolean publicOnly) {
            //前面的我得懒得管
            checkInitted();
            Method[] res;
            //老规矩我不看你的缓存的是啥
            ReflectionData<T> rd = reflectionData();
            if (rd != null) {
                res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods;
                if (res != null) return res;
            }
            // 拿不到之后的操作才是源头操作,很明显不出意外啊getDeclaredMethods0就是最终的获取方法,顺序问题重要接近尾声了,点进去就是结果了
            res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));
            if (rd != null) {
                if (publicOnly) {
                    rd.declaredPublicMethods = res;
                } else {
                    rd.declaredMethods = res;
                }
            }
            return res;
        }
    
        //居然是个native方法?裂开了啊
        private native Method[]      getDeclaredMethods0(boolean publicOnly);
      
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    想了想不能白分析啊,这就打开JDK源码,检索一下我们的getDeclaredMethods0,然后我们在Class.c文件找到了它

    static JNINativeMethod methods[] = {
        {"getDeclaredMethods0","(Z)[" MHD,      (void *)&JVM_GetClassDeclaredMethods},
    }
    
    • 1
    • 2
    • 3

    接下来就是找JVM_GetClassDeclaredMethods了,在jvm.h上对应着有

    JNIEXPORT jobjectArray JNICALL
    JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass, jboolean publicOnly);
    
    
    • 1
    • 2
    • 3

    在jvm.cpp上对应着有,看来又要去找get_class_declared_methods_helper了

    JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass, jboolean publicOnly))
    {
      return get_class_declared_methods_helper(env, ofClass, publicOnly,
                                               /*want_constructor*/ false,
                                               vmClasses::reflect_Method_klass(), THREAD);
    }
    JVM_END
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在get_class_declared_methods_helper,贴一下代码

    static jobjectArray get_class_declared_methods_helper(
                                      JNIEnv *env,
                                      jclass ofClass, jboolean publicOnly,
                                      bool want_constructor,
                                      Klass* klass, TRAPS) {
    
      JvmtiVMObjectAllocEventCollector oam;
    
      oop ofMirror = JNIHandles::resolve_non_null(ofClass);
      // Exclude primitive types and array types
      if (java_lang_Class::is_primitive(ofMirror)
          || java_lang_Class::as_Klass(ofMirror)->is_array_klass()) {
        // Return empty array
        oop res = oopFactory::new_objArray(klass, 0, CHECK_NULL);
        return (jobjectArray) JNIHandles::make_local(THREAD, res);
      }
    
      //结合下面的k->methods()我们知道,关键点在于InstanceKlass
      InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(ofMirror));
    
      // Ensure class is linked
      k->link_class(CHECK_NULL);
    
      //一眼就看到了我们熟悉的东西,methods,也就是其实找的就是k,咱们的instanceKlass的结构变量methods,问题不大
      Array* methods = k->methods();
      int methods_length = methods->length();
    
      // Save original method_idnum in case of redefinition, which can change
      // the idnum of obsolete methods.  The new method will have the same idnum
      // but if we refresh the methods array, the counts will be wrong.
      ResourceMark rm(THREAD);
      GrowableArray* idnums = new GrowableArray(methods_length);
      int num_methods = 0;
    
      for (int i = 0; i < methods_length; i++) {
        methodHandle method(THREAD, methods->at(i));
        if (select_method(method, want_constructor)) {
          if (!publicOnly || method->is_public()) {
            idnums->push(method->method_idnum());
            ++num_methods;
          }
        }
      }
    
      // Allocate result
      objArrayOop r = oopFactory::new_objArray(klass, num_methods, CHECK_NULL);
      objArrayHandle result (THREAD, r);
    
      // Now just put the methods that we selected above, but go by their idnum
      // in case of redefinition.  The methods can be redefined at any safepoint,
      // so above when allocating the oop array and below when creating reflect
      // objects.
      for (int i = 0; i < num_methods; i++) {
        methodHandle method(THREAD, k->method_with_idnum(idnums->at(i)));
        if (method.is_null()) {
          // Method may have been deleted and seems this API can handle null
          // Otherwise should probably put a method that throws NSME
          result->obj_at_put(i, NULL);
        } else {
          oop m;
          if (want_constructor) {
            m = Reflection::new_constructor(method, CHECK_NULL);
          } else {
            m = Reflection::new_method(method, false, CHECK_NULL);
          }
          result->obj_at_put(i, m);
        }
      }
    
      return (jobjectArray) JNIHandles::make_local(THREAD, result());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    找到instanceKlass.hpp,让我们直接找到methods()

      // 在这里
      Array* methods() const          { return _methods; }
      // 那必然是set干的顺序的事儿了啊
      void set_methods(Array* a)      { _methods = a; }
      Method* method_with_idnum(int idnum);
      Method* method_with_orig_idnum(int idnum);
      Method* method_with_orig_idnum(int idnum, int version);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    通过set_methods我们找到了classFileParser.cpp,在类加载的时候进行了调用

    void ClassFileParser::apply_parsed_class_metadata(
                                                InstanceKlass* this_klass,
                                                int java_fields_count) {
      assert(this_klass != NULL, "invariant");
    
      _cp->set_pool_holder(this_klass);
      this_klass->set_constants(_cp);
      this_klass->set_fields(_fields, java_fields_count);
      //就是这里
      this_klass->set_methods(_methods);
      
      //而_methods又经历了一次sort
      _method_ordering = sort_methods(_methods);
      
      
      //排一排
      static const intArray* sort_methods(Array* methods) {
      const int length = methods->length();
      if (JvmtiExport::can_maintain_original_method_order() || Arguments::is_dumping_archive()) {
        for (int index = 0; index < length; index++) {
          Method* const m = methods->at(index);
          assert(!m->valid_vtable_index(), "vtable index should not be set");
          m->set_vtable_index(index);
        }
      }
      
      //又再调用了Method的sort_methods
      Method::sort_methods(methods);
    
      intArray* method_ordering = NULL;
      if (JvmtiExport::can_maintain_original_method_order() || Arguments::is_dumping_archive()) {
        method_ordering = new intArray(length, length, -1);
        for (int index = 0; index < length; index++) {
          Method* const m = methods->at(index);
          const int old_index = m->vtable_index();
          assert(old_index >= 0 && old_index < length, "invalid method index");
          method_ordering->at_put(index, old_index);
          m->set_vtable_index(Method::invalid_vtable_index);
        }
      }
      return method_ordering;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    于是我们跟随脚步来到了method.cpp

    void Method::sort_methods(Array* methods, bool set_idnums, method_comparator_func func) {
      int length = methods->length();
      if (length > 1) {
        if (func == NULL) {
          //就这个传递进来的方法排序比较器,找一找
          func = method_comparator;
        }
        {
          NoSafepointVerifier nsv;
          QuickSort::sort(methods->data(), length, func, /*idempotent=*/false);
        }
        // Reset method ordering
        if (set_idnums) {
          for (int i = 0; i < length; i++) {
            Method* m = methods->at(i);
            m->set_method_idnum(i);
            m->set_orig_method_idnum(i);
          }
        }
      }
    }
    
    
    static int method_comparator(Method* a, Method* b) {
      //啥?为啥是按照名字排的啊?那。。。。肯定不是按照名字来了
      return a->name()->fast_compare(b->name());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在method.cpp里我们可以看到#include “oops/constMethod.hpp”,对应的在constMethod.hpp中,原来你name是个Symbol啊

      Symbol* name() const                           { return constants()->symbol_at(name_index()); }
    
    • 1

    而在Symbol.hpp中我们可以找到fast_compare,看到注释我们也知道了为了速度,采用的是Symbol的地址来比较的,每次启动在C_HEAP分配时这个地址先后顺序就没法保证了。

    // Note: this comparison is used for vtable sorting only; it doesn't matter
    // what order it defines, as long as it is a total, time-invariant order
    // Since Symbol*s are in C_HEAP, their relative order in memory never changes,
    // so use address comparison for speed
    int Symbol::fast_compare(const Symbol* other) const {
     return (((uintptr_t)this < (uintptr_t)other) ? -1
       : ((uintptr_t)this == (uintptr_t) other) ? 0 : 1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    C++ Reference: Standard C++ Library reference: C Library: cwchar: wcsftime
    Xcode15 framework ‘CoreAudioTypes‘ not found
    uniapp上echarts地图钻取
    【操作系统】内核支持线程和用户级线程
    C++项目:高并发内存池
    基于深度学习的宋词生成
    3.5 Keepalived双主热备
    局域网靶机渗透操作指南
    传输层中的TCP和UPD协议
    企业架构LNMP学习笔记11
  • 原文地址:https://blog.csdn.net/z327092292/article/details/127690428