昨天在写代码中,发现了一个有趣的现象
简单描述一下过程
name()
方法返回一个 String
类型;Test.name
;Main
函数进行执行,发现这两个对象运行时,竟不是同一个对象;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);
}
}
1
siweipancc 2022-07-13 11:28:46 +08:00 via iPhone 2
看这个,自己可以 debug 一下注解运行时。
https://stackoverflow.com/questions/37853188/why-are-annotation-string-values-not-interned |
2
L0L OP @siweipancc Thranks ,我再去试一下
|
3
lancelee01 2022-07-13 11:49:40 +08:00
会不会是由于每个变量都可以设置注解 name 属性的值,所以这个地方每次都是新建的
|
4
L0L OP @lancelee01 1 楼的大佬是正解
|
5
L0L OP @L0L
debug 了一波,简单总结下: 1. 注解中的方法默认使用了的静态常量值;经过反射获取到的该默认值,与原本的静态常量值对象是不相同的(!=); (注解的默认值通过 `AnnotationParser.parseMemberValue` 重新产生了一个新的对象) 2. 不同的属性(方法,类等)上的注解,通过反射获取到的注解实例,都是不同的对象(!=); (注解对象是通过 JDK 动态代理生成的,所以每一个都是不同的呢) 3. 不同的注解实例,如果使用的都是默认值的话,每一个默认值的对象都是相同的(==); (该对象存储在 AnnotationType 上[我理解为一层 java 缓存],通过 cas 保证线程安全) 4. 如果显示的指定具体注解的值(即使是静态常量值),最终获得的默认值对象都是不相同的(!=); (每一个注解的默认值,都是通过 `AnnotationParser.parseMemberValue` 产生的,顾与 **1** 是一致的 ) JVM 层为什么没有使用到常量池,还在学习 ing (暂时看不懂 CPlusPlus o(╥﹏╥)o ); 欢迎大家指正... |