java学习_有趣代码片段(一)

来源:互联网 发布:mac开发人工智能软件 编辑:程序博客网 时间:2024/06/05 20:28

记一个有趣的代码片段

昨天看到一个十分有意思的问题,当时看到问题的我也是瞬间懵了。其实就是自己掌握的知识不扎实。现在我把它分开经行解析下,如有不对,请指正!主要还是自己对基础知识理解的不扎实,以后还会遇到许许多多的问题,就干脆起了个java学习有趣代码片段(一)。

第一个问题

代码如下

package com.zhb;public class Test {    static Test test = new Test("3");    static{        System.out.println("1");    }    {        System.out.println("2");    }    Test(String s){        System.out.println(s);    }    public static void staticFunction(){        System.out.println("4");    }    public static void main(String[] args) {        staticFunction();    }}

看到这段代码,我心想我刚刚总结了关于static代码块的总结,这个还不在话下!结果应该是 1 2 3 4 。
运行后,我发现,什么鬼!
* 正确的运行结果:2 3 1 4 *

拆解分析

1.首先我们先再复习下关于代码块的知识
package com.zhb;public class Demo1 {    /**     * 静态代码块     */    static{        System.out.println("静态代码块");    }    /**     * 构造代码     */    {        System.out.println("构造代码块");    }    /**     * 无参构造函数     */    public Demo1(){        System.out.println("无参构造函数");    }    /**     * 有参数的构造函数     */    public Demo1(int num){        System.out.println("有参数的构造函数");    }    public static void main(String[] args) {        System.out.println("==================");        new Demo1();        System.out.println("==================");        new Demo1(2);    }}

执行结果
静态代码块

==================
构造代码块
无参构造函数

==================
构造代码块
有参数的构造函数

从中我们可以看出

  • 静态代码块它是随着类的加载而被执行,只要类加载了就会执行,而且只加载一次,主要用于给类进行初始化;
  • new一个对象的时候总是先执行构造代码,在执行构造函数,但是有一点需要注意构造代码不是在构造函数之前运行,它是依托构造函数执行。

  • 构造代码块每创建一个对象时,就会执行一次。同时构造函数是给特定的对象进行初始化,而构造代码是给所有的对象进行初始化,作用域不同。

  • 执行顺序:静态代码块> 构造代码块 > 构造函数

2,重现原题中的结构代码
package com.zhb;public class Demo2 {    static Demo1 demo1 =new Demo1() ;    /**     * 静态构造代码     */    static{        System.out.println("Demo2静态构造代码块");    }    /**     * 构造代码     */    {        System.out.println("Demo2构造代码块");    }    /**     * 无参构造函数     */    public Demo2(){        System.out.println("Demo2无参构造函数");    }    /**     * 有参数的构造函数     */    public Demo2(int num){        System.out.println("Demo2有参数的构造函数");    }    public static void main(String[] args) {        System.out.println("==================");        new Demo2();        System.out.println("==================");        new Demo2(2);    }}

执行结果:
静态代码块
构造代码块
无参构造函数
Demo2静态构造代码块

==================
Demo2构造代码块
Demo2无参构造函数

==================
Demo2构造代码块
Demo2有参数的构造函数

从中我们知道

  • 静态变量和静态构造代码块是同级别的;
  • static按照顺序执行
进一步演练
package com.zhb;public class Demo2 {    //static Demo1 demo1 =new Demo1() ;    static Demo2 demo2 =new Demo2() ;    /**     * 静态构造代码     */    static{        System.out.println("Demo2静态构造代码块");    }    /**     * 构造代码     */    {        System.out.println("Demo2构造代码块");    }    /**     * 无参构造函数     */    public Demo2(){        System.out.println("Demo2无参构造函数");    }    /**     * 有参数的构造函数     */    public Demo2(int num){        System.out.println("Demo2有参数的构造函数");    }    public static void main(String[] args) {        System.out.println("==================");        new Demo2();        System.out.println("==================");        new Demo2(2);    }}

此时的代码结构和原题是一样的。

  • 顺序执行静态部分,首先执行 static Demo2 demo2 =new Demo2() ;

  • 此时,new一个对象的时候总是先执行构造代码。
    执行System.out.println(“Demo2构造代码块”);

  • 执行构造函数 System.out.println(“Demo2无参构造函数”);此时demo2 结束

  • 顺序执行静态构造代码

  • 后面的正常执行(前面已解释)

执行结果:
Demo2构造代码块
Demo2无参构造函数
Demo2静态构造代码块

==================
Demo2构造代码块
Demo2无参构造函数

==================
Demo2构造代码块
Demo2有参数的构造函数

此时明白了原程序为什么是那样的结果了

第二个问题

我们把原题的程序修改成如下

package com.zhb;public class Test {    static Test test = new Test();    Test test2 = new Test();    public static void main(String[] args) {    }}

执行后报错

  • Exception in thread “main” java.lang.StackOverflowError *

这个问题是为什么呢?

静静的分析下

1.我们知道首先运行static.
2.static Test test = new Test(); 初始化Test类,会把类的成员变量实例化
3.实例化test2,但是Test test2 = new Test();此时又会实例化test2,一直进行循环
4.导致栈溢出

这里又引出一个问题:类的实例变量初始化的过程

class B {  private int b = 10;  public B(){    b = 100;  }}

编译成class文件后,使用命令 javap -c B.class 反编译

// 第一部分:父类的<init>()方法0: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V// 第二部分:实例变量初始化,也就是定义变量时的赋值4: aload_05: bipush        107: putfield      #2                  // Field b:I// 第三部分:构造函数方法体10: aload_011: bipush        10013: putfield      #2                  // Field b:I16: return

学习到这里总结一下前面学习的内容就是:
* Java实例变量在初始化时的顺序是父类的初始化代码(xxx—>xxx—>xxx)—>定义变量时直接赋值—>构造函数代码块。*

由于我也是菜鸟一枚,很多也是一知半解,如有不对,请指正。

参考:

1.http://blog.csdn.net/chenssy/article/details/14486833
2.http://blog.csdn.net/cauchyweierstrass/article/details/48943077

0 0