我敢打赌你做不了这道java题

java基础题

要是java笔试遇到这个题目,你知道答案吗?

The following program is correct? If wrong, please point out where is wrong. If not please write the answer.
public class TestJava {
    public static void main(String[] args) {
            Other other = new Other();
            new TestJava().addOne(other);
            System.out.println(other.i);
    }
    public void addOne(final Other other) {
            other.i++;
    }
}

class Other {
    public int i;
}

这道题目不难,java基础扎实的,一看便知答案!BUT, 本篇重点是通过这道题,来了解,我们忽略的一些细节。(Follow me!)原谅我的这次BiaoTiDang

容易错误点

上面有困惑的或许是:

  • 在static main方法中能实例化该类本身么?
  • final修饰的变量是能改变的?

针对本题,static修饰方法中,只要Other类型变量是局部的就可以在static方法中实例化。 ===》 没毛病
final修饰的变量不能再重新赋值,但是 other.i++ 操作并没有让other本身在JVM中的地址改变. ===》 没毛病

public class TestJava {
    public static void main(String[] args) {
        Other other1 = new Other();
        System.out.println("other1: " + other1);

        new TestJava().addOne(other1); 
        System.out.println(other1.i);
    }
    public void addOne(final Other other1) {
        System.out.println("other1:111 " + other1);
        other1.i++;
        System.out.println("other1: 222 " + other1);
    }
}

执行结果如下:3处other所标记的内存地址都是一样的。

other1: javaTest.Other@1540e19d
other1:111 javaTest.Other@1540e19d
other1: 222 javaTest.Other@1540e19d
1

针对final疑问点,可以修改如下:

public static void main(String[] args) {
        Other other1 = new Other();
        System.out.println("other1: " + other1);

        Other other2 = new Other();
        System.out.println("other2: " + other2);

        new TestJava().addOne(other1, other2);
        System.out.println(other1.i + ", " + other2.i);
    }
    public void addOne(final Other other1, Other other2) {
        System.out.println("other1: " + other1);
        System.out.println("other2: " + other2);

        //other1.i = other2.i;
        other1 = other2;
        other1.i++;
    }

注意其中的 final, 本段程序会报错,other1 无法 再次赋值 other2

addOne(final Other other1, Other other2) 

java代码执行顺序

问题1

先来看一段代码, 请问一下代码打印多少? 答案在

public class TestJava {
    private static int a = 10;
    {
        a = -1;
        System.out.println("block, a = " + a);
    }
    static {
        System.out.println("static, a = " + a);
    }
    public static void main(String[] args) {
        System.out.println("main, a = " + a);
    }
}

答案是:

static, a = 10
main, a = 10

为何没有 block, a = 10, 因为没有初始化 TestJava这个类!

了解java的,应该知道有关static描述,其中有一句是

static属于类本身, 不属于类的实例。

所以,上述代码执行顺序是,

  • 1.类中的static代码片段
  • 2.static main方法

问题2

再加上一行代码:

public static void main(String[] args) {
        System.out.println("main, a = " + a);
        new TestJava(); //新增代码
    }

答案

static, a = 10
main, a = 10
block, a = -1  //打印出来

类中在方法外的{}语句属于类实例, 会在类构造方法中执行!

为什么这么说? 不信请看 TestJava.class中内容。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package javaTest;

public class TestJava {
    private static int a = 10;

    public TestJava() {
        a = -1;
        System.out.println("block, a = " + a);
    }

    public static void main(String[] args) {
        System.out.println("main, a = " + a);
        new TestJava();
    }

    static {
        System.out.println("static, a = " + a);
    }
}

以上是.class文件在IntellJ IDE上的结果。发现 java源码文件{ }中的内容,跑到TestJava构造方法中了。这个也印证了

java程序没写构造方法,编译器会默认添加一个无参构造方法, 如果添加构造方法后,默认方法消失!

问题3 主动添加构造方法

添加构造方法后的 代码片段:

TestJava(int x) {
        a = x;
        System.out.println("TestJava(x), a = " + a);
    }
.....
public static void main(String[] args) {
        System.out.println("main, a = " + a);
        new TestJava(8); //修改后
    }

运行结果:

static, a = 10
main, a = 10
block, a = -1
TestJava(x), a = 8

通过.class查看 就知道为什么了.

... ...
TestJava(int x) {
        a = -1;
        System.out.println("block, a = " + a);
        a = x;
        System.out.println("TestJava(x), a = " + a);
    }
... ...

java编译器会将外部的{代码片段}包含到构造方法中,并且代码片段位于构造方法顶部。

问题4

要是TestJava中存在多个构造方法,那么 外部的代码片段会在每个构造方法中存在吗? 请看实验!
上述代码再添加无参数构造方法

... ...
public TestJava() {
        System.out.println("TestJava(), a = " + a);
    }
... ...

对应的.class文件显示:

public TestJava() {
        a = -1;
        System.out.println("block, a = " + a);
        System.out.println("TestJava(), a = " + a);
    }

    public TestJava(int x) {
        a = -1;
        System.out.println("block, a = " + a);
        a = x;
        System.out.println("TestJava(x), a = " + a);
    }

{代码片段} 会存在于每一个构造方法中, 而且位置在顶部!

java类中存在多个构造方法,那么 外部的 {代码片段} 会在每个构造方法中存在!

小结

通过以上示例,可以明白java中的几个概念

  • java代码加载顺序: **static { 代码片段 } -> static main方法(如果存在) ->类构造方法(如果存在) 合并外部 {代码片段} **
  • static属于类本身
  • final是不变,但是也可以让内容变

你可能感兴趣的:(我敢打赌你做不了这道java题)