Java之类字面常量

系列文描述

  该文章是日常笔记系列的第二篇,记录了类字面常量的特殊性,相信看完肯定有所收获。

关于类字面常量

描述:

最近接触了比较多的反射,了解到类字面常量特殊的地方,故做笔录,同时也和大家分享下类字面常量特殊在哪里。所谓的类字面常量指的是A.class,这是java提供的生成对Class对象的引用。关于类的概念我们都很熟悉,关于类的使用JDK大致为我们做了三步操作,分别是

  • 加载,这是由类加载器执行的,用白话来描述就是查找这个类的字节码,然后构建一个Class对象。
  • 链接,在这个阶段会先校验类的字节码,并且为类对象的静态域分配好内存空间。
  • 初始化,首先会先初始化类的超类(前提是有超类),以及执行静态初始化器和静态初始化块。

了解了三步还不够,我们还要知道jdk其实超级无敌懒的,对类的初始化这一步会延迟到对静态方法或者“非”常静态域进行首次引用时才执行。这里的常静态域指的是被static final修饰的常量,该常量不需要对应类初始化就可以被读取。为了更加清晰的了解到这个过程,可以看以下demo。

代码演示:

 
  1. package classLoader;
  2.  
  3. import java.util.Random;
  4.  
  5. class Initable1 {
  6.  
  7. static final int staticFinal = 47;
  8. static final int staticFinal2 = (int) (Math.random() * 1000);
  9.  
  10. static {
  11. System.out.println("Initializing Initable1");
  12. }
  13. }
  14.  
  15. class Initable2 {
  16.  
  17. static int staticNonFinal = 147;
  18.  
  19. static {
  20. System.out.println("Initializing Initable2");
  21. }
  22. }
  23.  
  24. class Initable3 {
  25.  
  26. static int staticNonFinal = 74;
  27.  
  28. static {
  29. System.out.println("Initializing Initable3");
  30. }
  31. }
  32.  
  33. public class ClassInitialization {
  34.  
  35. public static Random random = new Random(47);
  36.  
  37. public static void main(String[] args) throws ClassNotFoundException {
  38.  
  39. Class initable1 = Initable1.class;
  40. System.out.println("After creating Initable1 ref");
  41. System.out.println(Initable1.staticFinal);
  42. System.out.println(Initable1.staticFinal2);
  43. System.out.println(Initable2.staticNonFinal);
  44. Class initable3 = Class.forName("classLoader.Initable3");
  45. System.out.println("After creating Initable3 ref");
  46. System.out.println(Initable3.staticNonFinal);
  47. }
  48. }

看具体运行结果前,看官先自己用草稿写下输出答案哈,这样比较有效果。 运行结果如下:

 
  1. After creating INitable ref
  2. 47
  3. Initializing Initable1
  4. 604
  5. Initializing Initable2
  6. 147
  7. Initializing Initable3
  8. After creating Initable3 ref
  9. 74

如果答案一样,那么可以直接忽略掉我接下来的解析了哈,因为分析很绕,主要是验证上面的理论!

正如答案中看到的那样,47 在 After creating INitable ref 后才输出,证明了 Class initable1 = Initable1.class 这一行代码运行的时候并没有立即初始化类,而 Initializing Initable1 在47后才输出也验证了另一个观点(47对应的Field staticFinal是被static final 修饰的常静态域),那就是常静态域不需要在类Initable1进行初始化就可以被读取。而在打印结果Initable1.staticFinal2(随机数)之前先打印出了Initable1静态代码块中的输出,意味着直到这一步才真正初始化了类Initable1,于是先执行了静态代码块再输出了Initable1.staticFinal2,同样,对Initable2.staticNonFinal的输出先打印了Initable2静态代码块中的Initializing Initable2也是同样的原因。而在最后使用Class.forName("classLoader.Initable3")取得Initable3类的引用的时候直接打印了代码块中的字符串可以看出,使用Class.forName取得类的引用的时候是立即初始化类的。

结尾说点什么

说好的一周一篇,上个周末沉迷docker的使用导致废了,然后最近又是每天都是差不多十二点下班,所以只能下班后花时间写总结最近的笔记了(  ̄▽ ̄)((≧︶≦)


系列博客可以关注公众号:

公众号.jpg

个人网站:http://myblog.lixifan.cn/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值