我敢打賭你做不了這道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是不變,但是也可以讓內容變
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,765評論 18 399
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,933評論 18 139
  • 對象的創建與銷毀 Item 1: 使用static工廠方法,而不是構造函數創建對象:僅僅是創建對象的方法,并非Fa...
    孫小磊閱讀 2,031評論 0 3
  • 圖片發自簡書App 早安,今天早餐:番茄鵪鶉蛋面+桃膠銀耳 這是我第一次吃桃膠,同事小馮姐送的。我很慶幸自己一路走...
    營養學觀測閱讀 216評論 0 0
  • 或許這樣的想法很多人都有,所以《西部世界》才會這么火吧?我一邊看一邊這樣想著。 如果我們這個世界,只是更高維世界所...
    安達閱讀 1,002評論 0 49