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是不变,但是也可以让内容变