C爲何不能跨平臺
若是你們能對個人文章推薦一下,關注一下本人博客,那就更開心了,我從此也會更多的寫一些計算機系統/原理類的文章,以饗各位讀者。再次謝謝。前段時間看了 周志明的那本 《深刻理解java虛擬機》。對於平臺無關性問題,有了一些新的認識。因此特寫一篇博客來進行總結。html
這是個人第一篇不針對具體技術,而只針對計算機系統和原理的博客文章,而這種話題,老是比較寬泛,而我本人的水平有限,因此我也只能泛泛的寫寫,思考的不對的地方,還望讀者不吝批評。前端
C爲何不能跨平臺
我們先來討論一下,C語言的執行過程,從而搞清楚爲何C語言不能跨平臺。java
//@author www.yaoxiaowen.com 轉載文章請註明出處。 // 本文地址:http://www.cnblogs.com/yaoxiaowen/p/7470460.html #include <stdio.h> int main() { printf("Hello, World!"); return 0; }
以上就是廣大人民羣衆 都知道的hello world
程序。最終執行的結果 就是在console上輸出一行字符串, hello world!
。python
大學時,譚浩強的C語言教材,
main
方法的返回值是void
,但這是錯誤的。實質上應該返回int
來告訴操做系統執行結果。(固然,後來學習的深刻了,才知道譚的教材有很多錯誤的地方,可是我對這本教材依舊印象很好,由於那是我編程的啓蒙教材)。linux
咱們知道,計算機只認識0和1(就是二進制),換句話說,無論咱們在計算機上幹了什麼事情,運行了多麼複雜的程序,從ps繪圖,到qq聊天,再到聽音樂,最終到了CPU的執行層面,其實就是 一串串的0和1組成的指令罷了。 固然,到了硬件層面,那就是與或非門的領域了。可是,上面的那個 hello world
程序是怎麼轉換爲0和1的呢。
通常狀況下,對於咱們使用的是 IDE,好比 Visual Studio, CodeBlocks之類的,就是點擊個運行按鈕那麼簡單,或者你就是使用了gcc命令行來進行編譯,也能夠一行命令 gcc -o hello hello.c
,就 輸出了最後的編譯結果。可是實際上,hello world
的編譯過程是這樣的:c++
咱們分階段來討論:程序員
- 預處理階段。預處理器(cpp)來把 代碼中
#
開頭的行進行展開, 好比頭文件,宏等內容,修改最初的C文件。 - 編譯階段。編譯器(ccl)將修改後的C文件,翻譯成了 另外一文本文件,
hello.s
,這就是咱們所說的彙編程序了。 打開這個文本文件內容 相似下面的格式:
//@author www.yaoxiaowen.com 轉載文章請註明出處。 // 本文地址:http://www.cnblogs.com/yaoxiaowen/p/7470460.html section .data msg db 'Hello, world!',0xA len equ $-msg section .text global _start _start: mov edx,len mov ecx,msg mov ebx,1 mov eax,4 int 0x80 mov ebx,0 mov eax,1 int 0x80
固然,不一樣CPU和平臺環境,編譯輸出的彙編代碼也不一樣,咱們這裏僅做爲示例。數據庫
- 彙編階段。彙編器(as)將
hello.s
翻譯成機器語言指令。 把這些命令打包成一種叫作可重定位目標程序(relocatable object program)的格式,此時的輸出格式就是hello.o
了。這其實就是二進制文件了。 - 連接階段。編譯過程最後還有一個連接階段(程序調用了
printf
函數),最後的輸出結果仍是和上一步相似,都是直接二進制文件。
瞭解了 hello world
程序的編譯過程,咱們就來討論一下,什麼是彙編程序
。咱們先來看一下維基百科上的定義。(那個維基百科的連接,沒fan牆的同窗應該是打不開的)。編程
彙編語言(英語:assembly language)是一種用於電子計算機、微處理器、微控制器,或其餘可編程器件的低級語言。在不一樣的設備中,彙編語言對應着不一樣的機器語言指令集。一種彙編語言專用於某種計算機系統結構,而不像許多高級語言,能夠在不一樣系統平臺之間移植。
什麼是彙編,相關專業的同窗應該都明白,由於計算機只認識0和1(就是二進制),因此在計算機剛開始發明時,那些科學家們就是直接 向計算機輸入0和1,來運行計算任務的。(固然,他們是經過穿孔紙帶的方式來向計算機輸入, 好比有孔表明1,沒孔表明0)。經過這樣的方式,計算機終於能運行了,可是這樣的效率實在太慢了。
而在他們輸入的0和1中,有些表明的是指令,這些是有固定含義和編碼的。也是芯片能識別的。而另外一些是數據。這些不一樣的程序的數據天然是不一樣的。咱們前面就說,無論多麼複雜的計算機操做,到了cpu級別都是0和1,數據雖然多變,可是 指令的數量是有限的。由於 指令是要被芯片固定識別的。芯片中要用 晶體管(最初是電子管)組成的與或非門組合來識別這些指令和數據。由於直接輸入0和1,實在太繁瑣了,因此他們就發明了彙編語言。來簡化 程序的編寫。
好比 計算 1+1,兩個 數據1都 使用 0x0001
來表示,而 加操做,放在cpu中,能夠是 0xa90df
(這個是胡亂寫的),這個二進制表明的加操做能被計算機識別。而由於這個加操做對於cpu來講,編碼的0xa90df
格式是固定的。因此能夠直接一個助記符add
來表示,這樣科學家們寫程序就方便多了,而這就是彙編程序的由來。由於彙編程序完成以後,能夠再有一個專門的程序(就是要上文中所說的彙編器)來把編寫的彙編程序編譯成0和1.這樣計算機也能夠識別了,而彙編語言自己也方便了程序的編寫和閱讀。
編寫彙編比直接編寫二進制方便高效了太多。可是 隨着計算任務的複雜,程序的規模愈來愈龐大,使用匯編程序也很累啊,那麼是否有更簡單的方式呢?因此科學家們發明了高級語言(好比 C
,lisp
等),在編寫程序的時候,使用C語言等編寫,而後再使用 編譯器將C語言程序翻譯成彙編程序,彙編程序再使用彙編器編譯成0和1,這樣,cpu能識別的東西沒有變化,可是對於編寫程序的人,確實方便了不少。
經過以上的描述,咱們就知道了高級語言的大概由來。也明白了咱們所編寫的各類高級語言,到了最後,其實都是轉化爲二進制執行。
而直接二進制格式的程序,咱們稱之爲本地機器碼(native code)。而相似那些 add
之類的 助記符,以及彙編的編寫格式或標準,咱們稱之爲 指令集。
可是問題的關鍵來了。不一樣公司所生產的 cpu芯片。他們所使用的指令集不一樣啊, 這種芯片設計的事情,又不像TCP/IP協議那樣,有國際統一的標準,甚至像intel所表明的複雜指令集,和arm爲表明的精簡指令集,它們指令集的設計思路就是不同的。
因此 咱們C語言最後編譯出來的的二進制文件,假設是這段93034030930900090222ab2d11cd22dfad
(隨便寫的),不一樣的cpu上識別的意義是不一樣的。
因此爲何說C語言不能實現跨平臺運行,就是由於它編譯出來的 輸出文件的格式,只適用於某種cpu,其餘cpu不認識啊。
- 咱們所說的跨平臺運行,並非指
hell.c
這個文本文件的運行。由於文本文件自己也沒辦法運行。運行的只是它的編譯結果hello
,而這個由0和1組成的編譯結果,不一樣的cpu和平臺,他們的格式不一樣。因此C
語言編譯出來的結果,沒辦法跨平臺運行。
- 甚至在不一樣的平臺下,
hello.c
最後所編譯出來的文件的格式都不一樣。好比linux下編譯出的hello
,window下編譯結果是hello.exe
,而mac下編譯結果是hello.out
,(至於單片機上編譯結果的後綴是啥子,這個忘記了)。
- 也有些人會講,爲了讓linux下編寫的一段
hello
程序運行在window
上,我不拿最後的編譯結果hello
來直接運行,我在window環境下從新用IDE創建項目,一樣的源代碼在window下從新運行一遍,輸出hello.exe
,再在window上運行,行不行啊?這個答案是No。由於不一樣環境下,c語言的標準有差異。例如 int類型,在有的平臺上 可能16位表示,而有的平臺上則是32位表示。因此不一樣環境下的同一個程序,會存在數據溢出之類的錯誤。
- 其實還有一點,你們平時寫個程序,IDE上點擊個run/build之類的,稍等一會就輸出結果了,可是實際上,不少大型程序的編譯過程是比較長的,好比我第一家公司作手機系統的,編譯一個Android5.0的系統rom,在i7 cpu,16G內存的電腦上,須要編譯運行一個多小時,才能編譯成功輸出最後的結果。
知道了 C語言不能跨平臺運行,那有沒有一種辦法,可以 讓高級語言實現跨平臺的運行呢?
思考實際編程中的一個場景,咱們前端須要處理的某個數據是A格式,可是後臺只能提供B格式的數據,那咱們怎麼辦?很簡單啊。寫個接口,把B格式轉化爲A格式不就好了嘛。這就是設計模式當中的適配器設計模式。
關於跨平臺也是同樣的道理。cpu的指令集不一樣, 不一樣平臺編譯出來的結果格式都不一樣,那麼咱們能夠在各個平臺上運行虛擬機,而後咱們制定某種編譯結果的輸出格式,咱們的輸出了某種格式的結果,直接在虛擬機上運行。這樣不就ok了嘛。。
這其實就是 java採起的方式。
Class文件格式,虛擬機以及 ByteCode
這是java版本的helloJava
;
//@author www.yaoxiaowen.com 轉載文章請註明出處。 // 本文地址:http://www.cnblogs.com/yaoxiaowen/p/7470460.html public static void main(String[] args) { System.out.println("helloJava"); }
這段java程序編譯出來的結果是 helloJava.class
,換句話說,它輸出的結果是Class文件格式(也叫字節碼存儲格式)。
class文件的內容大概就像下面那樣:
是否是看不懂?看不懂就對了。這其實就是java虛擬機定義的二進制格式,這種咱們稱之爲 字節碼(ByteCode),是java虛擬機所能運行的格式。相似本地機器碼能夠反編譯成彙編,這種二進制也能夠反編譯成更容易閱讀的格式。
相似下面這樣。
而各個平臺的java虛擬機 是不一樣的。可是咱們編寫的java程序 統一編譯成特定格式的 Class文件格式,而後Class文件能夠在各個不一樣平臺的java虛擬機上運行,固然運行結果確定也是一致的,至於各個不一樣平臺之間的差別,這是那些編寫java虛擬機的人去考慮的事情,咱們這些作java的程序員,不用去關心這個問題。
經過這種方式,咱們的java程序就實現了跨平臺。
因此java也被稱爲 中間件技術語言。意思就是 中間加一層過分。很好理解。(固然,維基百科上對中間件技術的解釋,基本把我看暈了,也和java不要緊,不過你們理解這個意思就好)。
平臺無關性
而經過java虛擬機和Class文件格式,咱們就實現了平臺無關性,換句話說,這些適應各個不一樣平臺和cpu的工做的仍是要有人乾的。那就是設計java虛擬機的人去作這些工做,可是他們的辛苦換來了咱們上層程序員的輕鬆。咱們就徹底不關心各個平臺和cpu的差別了。
代碼編譯的結果,從本地機器碼(NativeCode)向字節碼(ByteCode)的轉變,是存儲格式的一小步,倒是編程語言發展的一大步
雖說名字是 ByteCode,可是我覺的,其實和 NaticeCode 都差很少,反正都是定義了一套指令集,只是前者能被虛擬機執行引擎去執行,而 後者能被物理機的CPU去執行罷了。
知道了大概的原理,咱們就思考另外一個問題,java虛擬機去執行Class文件,那和java的源文件 有什麼關係呢。答案是 不要緊。換句話說,java的源文件編譯的輸出結果爲Class文件,而Class文件能被java虛擬機認識,並執行,這是兩個獨立的過程,中間也沒啥關係和必然性。
那麼進而引伸出另外一個問題,某一種其餘編程語言,若是我設計出了一種對應的編譯器,將其編譯輸出結果爲Class文件,那這樣該語言豈不是也實現了跨平臺了?
想到這一點,那麼恭喜你,你發現了 java虛擬機的另外一種 重要特性。語言無關性
語言無關性
java虛擬機在執行Class文件時,不知道也徹底不關心這個Class文件是咋來的。(這個Class文件能夠是任何一種語言的源文件編譯而來,固然,就像直接編寫彙編同樣,你直接編寫 ByteCode也行,只要格式正確)。
其實CPU在執行二進制的指令時,它不知道也徹底不關心這些指令流是咋來的。這都是同一個道理。
不少程序員都還認爲Java虛擬機執行Java程序是一件理所固然和天經地義的事情。這是錯誤的。
下面某些內容 援引 周志明的 《深刻理解java虛擬機》:
Sun的開發設計團隊在最初設計的時候就把Java的規範拆分紅了Java語言規範《The Java Language Specification》及Java虛擬機規範《The Java Virtual Machine Specification》。
而且在1997年發佈的初版Java虛擬機規範中就曾經承諾過:「In the future,we will consider bounded extensions to the Java virtual machine to provide better support for other languages」(在將來,咱們會對Java虛擬機進行適當的擴展,以便更好地支持其餘語言運行於JVM之上)。
實現語言無關性的基礎仍然是虛擬機和字節碼存儲格式。Java虛擬機不和包括Java在內的任何語言綁定,它只與「Class文件」這種特定的二進制文件格式所關聯,Class文件中包含了Java虛擬機指令集和符號表以及若干其餘輔助信息。基於安全方面的考慮,Java虛擬機規範要求在Class文件中使用許多強制性的語法和結構化約束,但任何一門功能性語言均可以表示爲一個能被Java虛擬機所接受的有效的Class文件。做爲一個通用、機器無關的執行平臺,任何其餘語言的實現者均可以將Java虛擬機做爲語言的產品交付媒介。
換句話說,java虛擬機這個名字其實只是一個誤導,java虛擬機和java沒啥關係,其實更應該叫作 Class文件虛擬機。
由於其餘語言, 只要有對應的編譯器,輸出結果就能夠運行在java虛擬機上,因此時至今日,涌現Clojure、Groovy、JRuby、Jython、Scala一批運行在java虛擬機上的語言。
目前下圖中的語言都已經能夠運行在java虛擬機上。
因此廣義上的java技術體系,也包括Clojure、JRuby、Groovy,Scale等運行於Java虛擬機上的語言及其相關的程序。
Java,Scale等各類語言中的各類變量、關鍵字和運算符號的語義最終都是由多條字節碼命令組合而成的,所以字節碼命令所能提供的語義描述能力確定會比單一語言自己更增強大。
固然,在java最初剛出現的時候,Write Once,Run Anywhere, 這種 平臺無關性被吹噓的比較厲害,可是如今 這種虛擬機的思想,被不少其餘語言也學會了,好比python和pvm。go語言,.NET等都是一樣的思想。
爲何C/C++沒有被替代。
關於java虛擬機和Class文件格式, 貌似很厲害的樣子,什麼 我的一小步,人類一大步都扯上了,那確定有人疑問,爲何 c/c++這些不能跨平臺的語言,還如今還被不少人使用,還沒被java取代呢。
固然,這個緣由有不少,好比java的gc過程所沒法避免的stop the world過程,這在 某些實時性要求比較高的 系統中,好比 股票交易系統,軍事系統,是不可接受的。(關於垃圾回收這是另外一個話題,不在本文範圍內,將來有時間能夠花時間另寫博客討論這個問題)。
不過有句話說的很好
java和c++之間有一堵由動態內存分配和垃圾收集技術所圍成的'高牆',牆外的人想進去,牆內的人想出來
另外,對於直接與硬件交互的事情,也只能靠C語言了。畢竟上層再怎麼發展,硬件與系統之間永遠要存在一個驅動層啊。
可是除了以上這些,還有一個緣由。給你們講講軟件歷史上的一個重大教訓,你們也許就明白了。
當年爲了對抗sun的java平臺,微軟2002年推出了相似中間件思想的.NET平臺(C#)。當時window xp一統江湖,讓微軟如日中天,不可一世,微軟在下一代操做系統(就是window visa)的開發中,決定使用 C#, 雖然微軟牛逼哄哄,擁有最牛逼的程序員,最頂尖的科學家,可是開發到最後他們發現,使用C#這種運行在虛擬機上的中間件語言,不管如何也達不到 C/C++語言的速度。因此最後悲劇的 window visa,所有推倒重來,從新開發。當時李開復在微軟,他的一本書中對此有詳細介紹。
固然,當年window visa項目的失敗,還有其餘一些緣由,好比 使用數據庫系統代替文件系統,驅動不兼容等, 可是 使用.NET來進行開發,起碼也是失敗的主要緣由之一。
因此如今你們明白了,ByteCode運行在虛擬機上,相比於直接編譯成 NativeCode 運行在物理機上,速度較慢。
如今隨着虛擬機運行時優化技術的發展,以及硬件的速度愈來愈快,因此它們速度之間的差別,也沒以前差距那麼大了。
實質上,Class文件在虛擬機上運行的時候,還會有不少的優化措施。
在部分的商用虛擬機中,Java程序最初是經過解釋器(Interpreter)進行解釋執行的,當虛擬機發現某個方法或代碼塊的運行特別頻繁時,就會把這些代碼認定爲「熱點代碼」(Hot Spot Code)。爲了提升熱點代碼的執行效率,在運行時,虛擬機將會把這些代碼編譯成與本地平臺相關的機器碼,並進行各類層次的優化,完成這個任務的編譯器稱爲即時編譯器(Just In Time Compiler,簡稱JIT編譯器)。
許多主流的商用虛擬機都同時包含解釋器與編譯器。解釋器與編譯器二者各有優點:當程序須要迅速啓動和執行的時候,解釋器能夠首先發揮做用,省去編譯的時間,當即執行。在程序運行後,隨着時間的推移,編譯器逐漸發揮做用,把愈來愈多的代碼編譯成本地代碼以後,能夠獲取更高的執行效率。當程序運行環境中內存資源限制較大(如部分嵌入式系統中),可使用解釋執行節約內存,反之可使用編譯執行來提高效率。
可是實際上,編譯器能夠把java源文件的輸出結果編譯成Class格式(也就是 ByteCode),那天然也能夠有其餘類型的編譯器 能夠直接將java源文件編譯爲NativeCode啊。因此對於編程語言來講,咱們能夠有各類方式來編譯它,Java語言的「編譯期」實際上是一段「不肯定」的操做過程。由於咱們可使用不一樣類型的編譯器編譯出不一樣的輸出結果。
java常見的編譯器有如下類型。
- 前端編譯器:把.java文件轉變成.class文件。好比Sun的Javac、Eclipse JDT中的增量式編譯器(ECJ)。
- JIT編譯器:字節碼(ByteCode)轉變成機器碼(NaticeCode)。好比HotSpot VM的C一、C2編譯器。
- AOT編譯器:直接把*.java文件編譯成本地機器代碼。 好比GNU Compiler for the Java(GCJ)、Excelsior JET。
結束
因此討論到最後,你們就已經明白,因此平臺無關性,與 編譯器與編譯輸出結果格式 的關係。花了一天時間寫了這麼多內容,也但願給你們帶來一些啓發。
在本篇博客當中,不少內容也並非精確的分析,好比某些概念,都說的比較模糊,由於咱們這片博客只是討論思想。不少概念和過程也都沒有去深究, 若有錯誤不許確的地方,歡迎指正。
補充內容(20170905)
很是感謝你們對這篇文章的支持,可以對其餘人有所幫助,得到你們的承認。更加提高了我堅持寫博客的動力。
針對評論中的問題,也進行一些解答。
一
如文章末尾所說,我原本就是寫大概思想,因此不少細節沒有深刻去追究,其實好比像彙編的格式,指令集的執行等,其實這些討論起來真心複雜,牽扯到cpu的結構設計等。從此也計劃寫文章和你們討論這些問題。
評論中倒沒有人指出這方面的問題,不過我大學時原本就是作C語言和單片機的,明白這方面介紹的依舊不夠準確和詳細。(固然,不少細節我也忘記了)
二
評論當中有人提到.NET的虛擬機的問題,首先由於我自己是Android程序員,大學時期也作過C語言,單片機等,因此對java,C等算是瞭解一些,可是對.NET的確不瞭解。對.NET有限的知識,也來源於和作.NET的朋友的討論交流。所以關於.NET思想的評價可能不夠準確。
評論中有人提出瞭如下問題:
wdwwtzy 評論: 那我想問問,.net 也是 java 同樣的虛擬機技術,爲何早期.net 沒法跨平臺?
隆德爾評論:樓主,據我所知,java與.net,此虛擬機非彼虛擬機。並且這個問題一直被不少javaer所混淆。
wdwwtzy評論:啥意思,看文章的意思,java 一出生不就是真正的跨平臺了嗎?
有些同窗直接評論作了相關解答,對此深表感謝。寫博客原本就是一個相互討論相互促進的過程,因此感謝各位的解答。
WindyAmy評論:.net CLR/.net framework 和window系統結合的太緊密緻使。如今微軟重寫了部分framework庫(.net core),已經能夠實現誇平臺了。
Blackheart評論:由於沒有人在其餘平臺實現.net 的clr啊,後來有了mono,能夠跨平臺了。沒有真正意義上的跨平臺,對於開發者而已,可能你不須要關心操做系統是windows仍是linux了,你感受是跨平臺了。可是底層總有這麼一幫人在幫你搭建支撐「跨平臺」的基礎設施的,對於他們來講,一個個的平臺都須要單獨去實現的。**
幾位解答的同窗說的都已經很是好了,本人結合評論,也google了一些相關知識。再對.NET的相關問題寫出個人理解。以期拋磚引玉。
-
能夠肯定是,.NET和java虛擬機也是同樣的思想,都是引入中間層/虛擬機的思想。作java的同窗說java虛擬機(JVM),而微軟的.NET的虛擬機的名稱叫作通用語言運行平臺(Common Language Runtime,簡稱CLR)。雖然有些同窗可能認爲CLR不叫虛擬機,可是歸根到底,它仍是廣義的虛擬機的概念和思想。
-
Clojure、Groovy、JRuby、Jython、Scala等不少語言均可以運行在JVM上。而 CLR也是同樣的,C#、F#、VB.NET、C++、Python等幾十種語言也能夠運行在CLR上。
-
java,Scala等編譯結果爲ByteCode(字節碼),被稱之爲Class文件格式運行在jvm上,而jvm在運行Class格式文件時,能夠解釋運行,也能夠經過JIT編譯器編譯成NativeCode加快運行。而C#,C++等編譯成 通用中間語言(Common Intermediate Language,簡稱CIL),而後再彙編成字節碼,(固然這個字節碼確定不會是Class文件格式,可是概念相同),而在運行時,也是翻譯成本地機器碼運行(可是CLR貌似沒有解釋運行,這點求相關同窗解答,我估計應該也有相似javascript的解釋運行方式,不過沒查到相關資料)。
以上是技術層面,下面咱們再來討論 一些非技術層面。
你們知道,咱們要想在某個平臺上運行java開發的項目,必需要安裝jdk,這個過程仍是很麻煩的,要設置環境變量之類的。這對於普通用戶來說是不可能完成的操做。而.NET其實也是須要安裝環境的(叫作 .NET framework),可是window就是微軟自家的,因此window系統內置了.NET framewok。(win7自帶.net3.5版本,win10自帶4.0版本),因此window上原本就能夠運行.NET的程序。省去了普通用戶安裝.NET framework的麻煩。
可是微軟確定不會爲window內置jdk的,緣由太簡單了,若是window也都內置了jdk,而其餘的linux,mac等操做系統也都進行內置,那麼各個開發應用/遊戲的廠商們,直接使用java開發就行了,而後開發出來的產品直接window/linux/mac全部系統平臺上都通用,廠商們開心了,消費者也開心了,那這個時候,咱們爲何還要使用window操做系統呢?反正對於普通消費者而言,使用應用或玩遊戲都是沒啥區別的。
(因此這也是爲何java在pc端應用/遊戲領域沒人使用,而服務器端使用java的多,由於開發服務器的碼農們搭配java環境很easy啊)
回想一下 window與Netscape的瀏覽器大戰,若是使用瀏覽器就能幹大部分事情,那麼你們根本就不關心運行瀏覽器的操做系統是window仍是linux了。固然,如今互聯網的流量/入口之爭其實都是同一個道理。普通消費者哪裏關心那麼多,哪一個好用,哪一個便宜就用那個。
2014年11月12日,微軟宣佈將徹底開放.NET框架的源代碼,並提供給Linux和OS X使用。
首先本博客當中很是清晰的表達了這個觀點,什麼跨平臺不跨平臺,適應各個平臺/CPU的差別,這種髒活累活永遠也得有人幹,只是那些 去作虛擬機的人幹了這種活,咱們這種純粹寫上層的人輕鬆了而已。
因此我覺的不少時候,能不能跨平臺,除了技術問題,還要有商業緣由,甚至也有money的問題(畢竟開發各個平臺的虛擬機也是不易)。就像 .NET理論上跨平臺,可是不開源,幾年前微軟又不願爲.NET提供linux環境下的實現。那麼天然沒辦法跨平臺,可是這和技術無關。
java最初設計時,理論上就能夠跨平臺,可是那些苦逼的虛擬機開發者們還要去開發各個平臺/cpu的虛擬機,這也不是一朝一夕之功。
微軟如今可讓.NET跨平臺,一來大的形勢變了(以前的操做系統賣的那麼貴,如今win10均可以避免費了),二來微軟對.NET有控制權。而在java剛出來的時候,微軟也支持java,也設計過微軟版本的jvm。可是微軟是想擁有對java技術體系的控制權,可是發現搞不過sun之類的,java不在它的控制之下,因此微軟就開始搞本身的.NET平臺了。
也許Java程序員聽起來可能會以爲驚訝,微軟公司曾經是Java技術的鐵桿支持者(也必須認可,與Sun公司爭奪Java的控制權,令Java從跨平臺技術變爲綁定在Windows上的技術是微軟公司的主要目的)。在Java語言誕生的初期,微軟公司爲了在IE3中支持Java Applets應用而開發了本身的Java虛擬機,雖然這款虛擬機只有Windows平臺的版本,倒是當時Windows下性能最好的Java虛擬機。但好景不長,在1997年10月,Sun公司正式以侵犯商標、不正當競爭等罪名控告微軟公司,在隨後對微軟公司的壟斷調查之中,這款虛擬機也曾做爲證據之一被呈送法庭。這場官司的結果是微軟公司賠償2000萬美金給Sun公司(最終微軟公司因壟斷賠償給Sun公司的總金額高達10億美圓),承諾終止其Java虛擬機的發展,並逐步在產品中移除Java虛擬機相關功能。具備諷刺意味的是,到最後在Windows XP SP3中Java虛擬機被徹底抹去的時候,Sun公司卻又處處登報但願微軟公司不要這樣作。Windows XP高級產品經理Jim Cullinan稱:「咱們花費了3年的時間和Sun打官司,當時他們試圖阻止咱們在Windows中支持Java,如今咱們這樣作了,可他們又在抱怨,這太具備諷刺意味了。」
這個故事告訴咱們一個道理:早知今日,何須當初呢。