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是不變,但是也可以讓內容變