JAVA提供的「+」運算符,如Iteger+String,從C++的角度來看總是想找到JAVA是怎麼重載這個「+」運算符,於是進去String這個類別中看,然而並沒有什麼卵發現,於是乎想著JAVA是怎麼做到的?下面來為你逐步分析下JAVA是怎麼實現「+操作符重載的」。
範例
public class Example { public static void main(String[] args) { Integer a = null; String b = a + "456"; System.out.println(b); } }
這個程式很簡單就是一個Integer和String的「+」運算表達式。運行結果:null456
反編譯範例程式
指令:
javap -c Example
反編譯後的結果如下:
Compiled from "Example.java" public class com.boyu.budmw.test.Example extends java.lang.Object{ public com.boyu.budmw.test.Example(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: aconst_null 1: astore_1 2: new #2; //class java/lang/StringBuilder 5: dup 6: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V 9: aload_1 10: invokevirtual #4; //Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; 13: ldc #5; //String 456 15: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 18: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 21: astore_2 22: getstatic #8; //Field java/lang/System.out:Ljava/io/PrintStream; 25: aload_2 26: invokevirtual #9; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 29: return }
我們來分析下main函數部分:
0:將棧量nullull :從運算元堆疊中將null彈出儲存到索引為1的局部變數a中
2:new一個StringBuilder
5:複製先前new出來的空間並將其壓入運算元堆疊
6:呼叫進行初始化
9:將結果儲存到操作數棧
10:呼叫StringBuilder.append(java/lang/Object)
13:將「456」壓入頂棧
15:StringBuilder.append(java/lang /String)
18:執行toString函數
從上面的分析我們可以看到其最終是先生成了一個StringBuilder對象,之後的“+”操作符都是調用了StringBuilder.append()進行“+”的。這就可以解釋上面範例程式運行後為什麼是null456了,append object的時候呼叫了
public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); }
將object轉換為String了。
為什麼JAVA不支援操作符重載
像C++中類別對操作符進行了重載,個人覺得會操作維護難得問題,因為操作符重載沒有一個標準來約束大家都可以想當然的進行重載會造成語意相差大,可讀性嚴重降低,所以java中去掉操作子重載這個特性和他的高階物件導向很相符。 so,不糾結這個問題。
後記
這都是在開發過程中會經常使用的一些東西但是可能在平時開發過程中沒有挖的這麼深入,都想當然了,後面可以嘗試不斷挖掘這些不被發現的小case。