V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
L0L
V2EX  ›  程序员

Java 注解中 String 类型的 default 一些疑问

  •  
  •   L0L · 2022-07-13 11:08:03 +08:00 · 1499 次点击
    这是一个创建于 867 天前的主题,其中的信息可能已经有所发展或是发生改变。

    昨天在写代码中,发现了一个有趣的现象

    简单描述一下过程

    1. 初步定义了一个注解,其中一个 name() 方法返回一个 String 类型;
    2. 指定了其默认值为一个静态的对象 Test.name;
    3. 通过 Main 函数进行执行,发现这两个对象运行时,竟不是同一个对象;
    4. JetBrain 的反编译功能查看,发现 Test.name 被转换成了 ‘123’ 的常量值。

    其实这里更好奇的是,Java String Constant Pool 为什么没有起作用;

    目前怀疑点还是在内存分配的空间上:由于常量字符串池是在堆上分配,而注解是在非堆(这点不是很确认)?

    下面是代码:

    package com.example._17.demo.blog;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import java.lang.reflect.Field;
    
    public class Question {
    
        @Retention(RetentionPolicy.RUNTIME)
        @Target(ElementType.FIELD)
        @interface Test {
    
            String name = "123";
    
            String name() default name;
        }
    
        @Test
        public final String demo = "123";
    
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
            
            Field field = Question.class.getField("demo");
            Test annotation = field.getAnnotation(Test.class);
            System.out.println(annotation.name() == Test.name);
        }
    }
    
    
    5 条回复    2022-07-13 21:58:50 +08:00
    siweipancc
        1
    siweipancc  
       2022-07-13 11:28:46 +08:00 via iPhone   ❤️ 2
    L0L
        2
    L0L  
    OP
       2022-07-13 11:39:17 +08:00
    @siweipancc Thranks ,我再去试一下
    lancelee01
        3
    lancelee01  
       2022-07-13 11:49:40 +08:00
    会不会是由于每个变量都可以设置注解 name 属性的值,所以这个地方每次都是新建的
    L0L
        4
    L0L  
    OP
       2022-07-13 12:28:49 +08:00
    @lancelee01 1 楼的大佬是正解
    L0L
        5
    L0L  
    OP
       2022-07-13 21:58:50 +08:00
    @L0L
    debug 了一波,简单总结下:
    1. 注解中的方法默认使用了的静态常量值;经过反射获取到的该默认值,与原本的静态常量值对象是不相同的(!=);
    (注解的默认值通过 `AnnotationParser.parseMemberValue` 重新产生了一个新的对象)

    2. 不同的属性(方法,类等)上的注解,通过反射获取到的注解实例,都是不同的对象(!=);
    (注解对象是通过 JDK 动态代理生成的,所以每一个都是不同的呢)

    3. 不同的注解实例,如果使用的都是默认值的话,每一个默认值的对象都是相同的(==);
    (该对象存储在 AnnotationType 上[我理解为一层 java 缓存],通过 cas 保证线程安全)

    4. 如果显示的指定具体注解的值(即使是静态常量值),最终获得的默认值对象都是不相同的(!=);
    (每一个注解的默认值,都是通过 `AnnotationParser.parseMemberValue` 产生的,顾与 **1** 是一致的 )

    JVM 层为什么没有使用到常量池,还在学习 ing (暂时看不懂 CPlusPlus o(╥﹏╥)o );

    欢迎大家指正...
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2694 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 15:43 · PVG 23:43 · LAX 07:43 · JFK 10:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.