Java有意思的知识点
今天在论坛上看到的几个题,有几个貌似还挺有意思的。
public static void test() { String x = "hello"; String y = "world"; String z = new String("helloworld"); String a = "helloworld"; System.out.println("x == hello:" + (x == "hello")); System.out.println("a == helloworld:" + (a == "hello" + "world")); System.out.println("a == x+y:" + (a == (x + y))); } x == hello:true
a == helloworld:true
a == x+y:false
请看翻译过的源码:
public static void test(); 0 ldc <String "hello"> [15] 2 astore_0 [x] 3 ldc <String "world"> [17] 5 astore_1 [y] 6 ldc <String "helloworld"> [19] 8 astore_2 [a] 9 getstatic java.lang.System.out : java.io.PrintStream [21] 12 new java.lang.StringBuilder [27] 15 dup 16 ldc <String "x == hello:"> [29] 18 invokespecial java.lang.StringBuilder(java.lang.String) [31] 21 aload_0 [x] 22 ldc <String "hello"> [15] 24 if_acmpne 31 27 iconst_1 28 goto 32 31 iconst_0 32 invokevirtual java.lang.StringBuilder.append(boolean) : java.lang.StringBuilder [34] 35 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [38] 38 invokevirtual java.io.PrintStream.println(java.lang.String) : void [42] 41 getstatic java.lang.System.out : java.io.PrintStream [21] 44 new java.lang.StringBuilder [27] 47 dup 48 ldc <String "a == helloworld:"> [47] 50 invokespecial java.lang.StringBuilder(java.lang.String) [31] 53 aload_2 [a] 54 ldc <String "helloworld"> [19] 56 if_acmpne 63 59 iconst_1 60 goto 64 63 iconst_0 64 invokevirtual java.lang.StringBuilder.append(boolean) : java.lang.StringBuilder [34] 67 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [38] 70 invokevirtual java.io.PrintStream.println(java.lang.String) : void [42] 73 getstatic java.lang.System.out : java.io.PrintStream [21] 76 new java.lang.StringBuilder [27] 79 dup 80 ldc <String "a == x+y:"> [49] 82 invokespecial java.lang.StringBuilder(java.lang.String) [31] 85 aload_2 [a] 86 new java.lang.StringBuilder [27] 89 dup 90 aload_0 [x] 91 invokestatic java.lang.String.valueOf(java.lang.Object) : java.lang.String [51] 94 invokespecial java.lang.StringBuilder(java.lang.String) [31] 97 aload_1 [y] 98 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [57] 101 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [38] 104 if_acmpne 111 107 iconst_1 108 goto 112 111 iconst_0 112 invokevirtual java.lang.StringBuilder.append(boolean) : java.lang.StringBuilder [34] 115 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [38] 118 invokevirtual java.io.PrintStream.println(java.lang.String) : void [42] 121 return
对于String常量,包括“hello”+“world”这种方式的的值(第54行),都被设置为常量。然而对于x+y这种方式,其实首先是创建了一个StringBuilder,然后把两个变量都加到StringBuilder内,再转换成String。此时,就形成了一个新的String对象了。equals方法也就不适用了。
三、Override覆盖
public class Parent { public static String say() { return "parent static say"; } public String say2() { return "parent say"; } } public class Child extends Parent { public static String say() { return "child static say"; } public String say2() { return "child say"; } } public class OverrideTest { public static void main(String[] args) { Parent p = new Child(); System.out.println(p.say()); System.out.println(p.say2()); } } parent static say
child say
所谓静态方法,并不仅仅指该方法在所有实例中只有一份,同时也指该方法是“静态”加载的,即在编译期就已决定其行为。此处p的静态类型为Parent,所以它所调用的方法也在编译期和Parent的say()方法绑定:
// Method descriptor #15 ([Ljava/lang/String;)V // Stack: 2, Locals: 2 public static void main(java.lang.String[] args); 0 new com.ibm.oneteam.Child [16] 3 dup 4 invokespecial com.ibm.oneteam.Child() [18] 7 astore_1 [p] 8 getstatic java.lang.System.out : java.io.PrintStream [19] 11 invokestatic com.ibm.oneteam.Parent.say() : java.lang.String [25] 14 invokevirtual java.io.PrintStream.println(java.lang.String) : void [31] 17 getstatic java.lang.System.out : java.io.PrintStream [19] 20 aload_1 [p] 21 invokevirtual com.ibm.oneteam.Parent.say2() : java.lang.String [37] 24 invokevirtual java.io.PrintStream.println(java.lang.String) : void [31] 27 return
六、提前引用
public class ForwardReference { static int first = test(); static int second = 2; static int test() { return second; } public static void main(String[] args) { System.out.println("first = " + first); } } first = 0
这段代码有点诡异,但明白万变不离其宗,只要牢记静态方法&变量是“静态”加载的,即编译时就决定的即可。当然,对于静态变量的这种先定义后赋值的行为,还是需要小心:
public class com.ibm.oneteam.Main { // Field descriptor #6 I static int first; // Field descriptor #6 I static int second; // Method descriptor #9 ()V // Stack: 1, Locals: 0 static {}; 0 invokestatic com.ibm.oneteam.Main.test() : int [11] 3 putstatic com.ibm.oneteam.Main.first : int [15] 6 iconst_2 7 putstatic com.ibm.oneteam.Main.second : int [17] 10 return Line numbers: [pc: 0, line: 5] [pc: 6, line: 6] [pc: 10, line: 3] // Method descriptor #9 ()V // Stack: 1, Locals: 1 public Main(); 0 aload_0 [this] 1 invokespecial java.lang.Object() [22] 4 return Line numbers: [pc: 0, line: 3] Local variable table: [pc: 0, pc: 5] local: this index: 0 type: com.ibm.oneteam.Main // Method descriptor #14 ()I // Stack: 1, Locals: 0 static int test(); 0 getstatic com.ibm.oneteam.Main.second : int [17] 3 ireturn Line numbers: [pc: 0, line: 9]看这段代码也许更加直观点:
public class Main { static int first = test(); static int second = 2; static int test() { return second; } static int third = 3; public static void main(String[] args) { System.out.println("first = " + first); }}编译后的代码:
// Compiled from Main.java (version 1.6 : 50.0, super bit)public class com.ibm.oneteam.Main { // Field descriptor #6 I static int first; // Field descriptor #6 I static int second; // Field descriptor #6 I static int third; // Method descriptor #10 ()V // Stack: 1, Locals: 0 static {}; 0 invokestatic com.ibm.oneteam.Main.test() : int [12] 3 putstatic com.ibm.oneteam.Main.first : int [16] 6 iconst_2 7 putstatic com.ibm.oneteam.Main.second : int [18] 10 iconst_3 11 putstatic com.ibm.oneteam.Main.third : int [20] 14 return Line numbers: [pc: 0, line: 5] [pc: 6, line: 6] [pc: 10, line: 12] [pc: 14, line: 3] // Method descriptor #10 ()V // Stack: 1, Locals: 1 public Main(); 0 aload_0 [this] 1 invokespecial java.lang.Object() [25] 4 return Line numbers: [pc: 0, line: 3] Local variable table: [pc: 0, pc: 5] local: this index: 0 type: com.ibm.oneteam.Main // Method descriptor #15 ()I // Stack: 1, Locals: 0 static int test(); 0 getstatic com.ibm.oneteam.Main.second : int [18] 3 ireturn Line numbers: [pc: 0, line: 9] // Method descriptor #30 ([Ljava/lang/String;)V // Stack: 4, Locals: 1 public static void main(java.lang.String[] args); 0 getstatic java.lang.System.out : java.io.PrintStream [31] 3 new java.lang.StringBuilder [37] 6 dup 7 ldc <String "first = "> [39] 9 invokespecial java.lang.StringBuilder(java.lang.String) [41] 12 getstatic com.ibm.oneteam.Main.first : int [16] 15 invokevirtual java.lang.StringBuilder.append(int) : java.lang.StringBuilder [44] 18 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [48] 21 invokevirtual java.io.PrintStream.println(java.lang.String) : void [52] 24 return Line numbers: [pc: 0, line: 15] [pc: 24, line: 16] Local variable table: [pc: 0, pc: 25] local: args index: 0 type: java.lang.String[]}七、对象引用
public class TestRef { public static void main(String[] args) { StringBuffer a = new StringBuffer("a"); StringBuffer b = new StringBuffer("b"); append(a, b); System.out.println(a.toString() + "," + b.toString()); b = a; System.out.println(a.toString() + "," + b.toString()); } public static void append(StringBuffer a, StringBuffer b) { a.append(b); b = a; } } ab,b
ab,ab
这段代码就十分简单了,明白了引用拷贝就知道原因了。 1 楼 daly1987 2011-12-18 不错啊,加油