Java 中 statci 与 {} 与构造方法的一种使用技巧 – 热爱改变生活
我的GitHub GitHub |     登录
  • If you can't fly, then run; if you can't run, then walk; if you can't walk, then crawl
  • but whatever you do, you have to keep moving forward。
  • “你骗得了我有什么用,这是你自己的人生”
  • 曾有伤心之地,入梦如听 此歌

Java 中 statci 与 {} 与构造方法的一种使用技巧

Java sinvader 4079℃ 0评论

先来看一个常见的例子

来看 TestClass,我在 TestClass 中放了 static 代码块以及实例初始化和构造方法:

  1. package cn.sumile;
  2.  
  3. public class TestClass {
  4. int i = 2;
  5. {
  6. System.out.println("实例初始化" + i);
  7. }
  8. static {
  9. System.out.println("静态代码块");
  10. }
  11.  
  12. public TestClass() {
  13. System.out.println("构造函数" + i);
  14. }
  15.  
  16. public int getI() {
  17. return i;
  18. }
  19.  
  20. public void setI(int i) {
  21. this.i = i;
  22. }
  23. }
  1. new TestClass();
  2. System.out.println("==================");
  3. new TestClass();

上面是调用的代码,这个是它的调用结果:

  1. 静态代码块
  2. 实例初始化 2
  3. 构造函数 2
  4. ==================
  5. 实例初始化 2
  6. 构造函数 2

从上面我们知道了,在实例化这个类的时候,会首先调用类中的静态代码块(也就是:static{}),然后会开始调用构造块 (也就是:{}),然后才会调用 java 的构造方法。

那么,当我们像下面这样做的时候都发生了什么?

  1. System.out.println(
  2. new TestClass() {
  3. ParseError: KaTeX parse error: Expected '}', got 'EOF' at end of input: 1 {
  4. setI(3); setI(3);2 }
  5. }.getI()
  6. );
  7. System.out.println("================");
  8. new TestClass() {
  9. {
  10. i = 3;
  11. }
  12. };

上面那个,当我们用反编译工具对生成的.class 文件进行反编译之后我们可以看到:

  1. class MainClass1extendsTestClass1 extends TestClass
  2. ParseError: KaTeX parse error: Expected '}', got 'EOF' at end of input: {
  3. MainClass MainClass1()
  4. {
  5. setI(3);
  6. }
  7. }

可以看到,程序根据 11-2 之间的代码生成了一个文件,而这个文件的名称是这样的:XXX$1.class。

$后面跟数字是匿名类编译出来的

$后面跟文字是内部类编译出来的

由此我们知道了,MainClass$1 这个 class 文件是一个匿名内部类搞出来的,也就是这个代码搞出来的:

  1. {
  2. setI(3);
  3. }

那实际上在 new TestClass 的时候真正发生的是什么呢?

首先调用 static 代码块,然后调用 block 构造块,然后调用父类的构造方法,然后调用子类(MainClass$1.class)的构造方法,最后才会调用 setI(3)。至此,实例化 TestClass 完成。

测试代码下载(包含反编译工具)

扩展

希望看一下这个网页,我觉得挺有用的:Java 中 HashMap 初始化的另一种方式详解
关于这个网页里面说的最后的执行效率问题,我觉得应该是出在了每次都要对匿名内部类搞几个文件,这是之前他测试的代码:

  1. long st = System.currentTimeMillis();
  2. /*
  3. for (int i = 0; i < 10000000; i++) {
  4. HashMap<String, String> map = new HashMap() {
  5. {
  6. put("Name", "June");
  7. put("QQ", "2572073701");
  8. }
  9. };
  10. }
  11. System.out.println(System.currentTimeMillis() - st); // 1217
  12. */
  13.  
  14. for (int i = 0; i < 10000000; i++) {
  15. HashMap<String, String> map = new HashMap();
  16. map.put("Name", "June");
  17. map.put("QQ", "2572073701");
  18. }
  19. System.out.println(System.currentTimeMillis() - st); // 1064

所以我测试了下面的代码,发现他们所耗费的时间相差无几(实际上一会儿这个占用时间多一会儿那个占用时间多,可能跟电脑有关系,而不是每次都是第二个所耗费的时间比较多)

  1. HashMap map = new HashMap() {
  2. {
  3. for (int i = 0; i < 10000000; i++) {
  4. put("Name", "June");
  5. put("QQ", "2572073701");
  6. }
  7. }
  8. };
  9. System.out.println(System.currentTimeMillis() - st);
  10. long st2 = System.currentTimeMillis();
  11. HashMap<String, String> map2 = new HashMap();
  12. for (int i = 0; i < 10000000; i++) {
  13. map2.put("Name", "June");
  14. map2.put("QQ", "2572073701");
  15. }
  16. System.out.println(System.currentTimeMillis() - st2);

 

¥ 有帮助么?打赏一下~

转载请注明:热爱改变生活.cn » Java 中 statci 与 {} 与构造方法的一种使用技巧


本博客只要没有注明“转”,那么均为原创。 转载请注明链接:sumile.cn » Java 中 statci 与 {} 与构造方法的一种使用技巧

喜欢 (0)
发表我的评论
取消评论
表情

如需邮件形式接收回复,请注册登录

Hi,你需要填写昵称和邮箱~

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址