部分phper會考慮轉型go還是java,以下就這兩種語言進行簡單比較。本文僅供參考!
Go語言
相對於Java,Go語言是編譯成機器碼然後直接執行的。很大程度像C語言一樣。因為它沒有虛擬機,這一點和Java很不一樣。它是面向對象的,同時在某種程度上講,它並不僅僅是一種加入了自動垃圾收集機制的新的C語言。從一個Java程式設計師的角度來看,有些東西是如此不同,以致於學習Go語言變成一件極具挑戰性的事情,並且可以幫助更深入地理解程式語言結構,以及物件、類別和所有其他語言部件都是怎麼回事,連Java也是如此。
我的意思是如果你了解Go語言中的物件導向實作方式,那麼你也會理解Java語言中關於這些內容的不同實作方式。
是否使用垃圾回收
記憶體管理部分在程式語言中是至關重要的。組合語言可以讓你做所有的事情,或者更確切地說,它要求你做所有的事情。 C標準函式庫中提供一些關於記憶體管理的基礎功能,但這仍需要你在呼叫malloc分配記憶體後手動釋放他們。自動化記憶體管理技術隨著C ,Python,Swift和Java一起出現。 Go語言也是他們的其中一員。
對Java及其他JVM語言(包括Python的JVM實作)來說,記憶體由JVM來管理。 JVM有非常成熟的垃圾回收,垃圾回收一直在一個或更多的線程中運行----與工作線程並行或有時暫停這些工作線程來標記那些不可達對象,清除它們並將檢測到的分散的記憶體壓縮到一起。所有你需要擔心的只是性能。
Go語言也是使用的這種方式,不過仍有一些細微的差別。 Go語言沒有引用,但是有指標。這個不同非常重要。 Go語言可以和額外的C代碼集成,出於性能的原因,沒有像引用那樣在運行時註冊的東西。實際的指針對運行系統是透明的。分配的記憶體仍然可以被分析以收集為可達性的資訊並且無用物件仍然可以被標記和清除,只是記憶體不能被移到別處做壓縮。
Go語言有垃圾回收但不是像Java那樣完整的GC,因為它沒有對記憶體進行壓縮。這也不一定是壞事。因為這對伺服器長時間運行仍然不會產生記憶體碎片很有意義。有些JVM垃圾收集器在清楚舊生代時為了減少GC停頓也會跳過壓縮步驟,僅僅把壓縮當作最後的措施。 Go中沒有實施這個最後措施的步驟,這在某些罕見的情景中可能會帶來一些問題。當你學習這門語言時,你基本上不可能會遇到這個問題。
本地變數
在Java語言中,本機變數(以及在更新的版本中某些時候的物件)是儲存在堆疊上的。這在C,C 及其他實作了呼叫堆疊本身的語言也是如此。 Go語言也不例外,除非你從一個函數中簡單地傳回了一個指向本地變數的指標。這是C語言中的致命錯誤。對Go來說,Go的編譯器發現已分配的"物件"(稍後我會解釋這兒為何要用引號)從方法中逃逸,並據此分配這個它(內存),因此這個"對象"在函數返回後仍存活並且指向它的指標不會指向已經廢棄,資料不可靠的記憶體。
閉包
您可以在函數的內部寫函數,然後傳回此函數,就像函數式語言一般(Go語言是一種函數式語言) ,那麼局部變數在這個函數中就是一個閉包的變數。
函數傳回值
函數不僅可以只傳回單一值,還可以傳回多個值。如果沒有合理使用,這似乎是糟糕的實踐。 Python和Perl都是這樣的。傳回多個值在某些情況下很好用。它主要用於傳回值和‘nil’或錯誤碼。這樣,過去將錯誤編碼進返回類型(通常是像C的標準庫調用一樣返回-1作為錯誤碼,其他非負值代表其他意思)的習慣將會被這種可讀性更高的方式取代。
物件導向
由於將閉包和函數當作一等公民,Go至少可以實作JavaScript一樣的物件導向。但實際上Go有介面和結構體,可以做的更多。不過介面和結構體不是真正的類,它們是值類型。它們透過值傳遞,並且不論它們儲存在記憶體哪裡,它們儲存的資料都只是純的數據,不會有物件頭或任何類似物件頭的東西。 Go中的結構體與C中的結構體十分類似-它們都可以包含字段,但它們都不可以互相繼承或包含方法。物件導向的實作方式略有不同。
你可以在你定義方法本身時指定結構體,而不是把方法塞進類別定義。結構體也可以包含其他結構體,假如你要引用的欄位沒有名字,那麼你可以透過它的型別引用它,該型別也會隱含地成為該欄位的名字。或者只要這個欄位或方法屬於頂層結構體,你就可以引用它
當你要指定可以呼叫方法的結構體,你可以透過這個結構體自己指定或指向這個結構體的指標。如果方法應用於結構體,那麼該方法會獲得呼叫結構體的副本(這個結構體是透過值傳遞的)。如果方法應用於指向結構體的指針,那麼該指針將會被傳遞(類似透過引用傳遞)。在後一種情況下,方法還可以更改結構體(從這個意義上講,結構體不是值類型,因為值類型是不可變的)。兩種都可以用於滿足介面的需求。
Go的語法對結構體和指標也要寬容些。在C中,你可以用b.a來存取你擁有的結構體的a字段。對於C中指向結構體的指針,你則必須使用b->a存取相同的欄位。在使用指標的情況下b.a將會報錯。 Go認為寫成b->a毫無意義(對,就是這個意思)。為什麼在.操作符可以被重載時還要用->操作符使程式碼看起來雜亂?結構體可以這樣存取字段,那麼透過指標也應該這樣訪問,非常合乎邏輯。
類型在變數上而不是物件上
這就是我為什麼在"物件"上加上引號。當Go儲存一個結構體時,它就是一塊內存,它沒有物件頭,其實是變數包含了值的型別。如果變數是結構體類型,那麼我們在編譯時就已經知道了。如果變數是介面類型,那麼變數將會指向其值,同時引用值的實際類型。
實作介面
介面在Go中非常簡單,同時又非常複雜。介面聲明了一堆方法,如果結構體想與介面相容,它們必須實作這些方法。繼承介面和繼承結構體的方式相同。奇怪的是結構體實作一個介面時你不需要明確指定。實際上畢竟不是接構體實現了接口,而是這組函數把結構體或指向結構體的指標當作了接收者。如果介面所有的函數都被實現,那麼這個結構體實作了這個介面。如果部分函數沒有被實現,那麼這個實作是不完整的。
為什麼我們在Java中需要‘implements’關鍵字而Go不需要? Go確實不需要是因為它是完全編譯型的,而且沒有類似Java那樣在運行期間分別載入編譯程式碼的類別載入器的東西。如果一個結構體應該實作某個介面但卻沒有實現,那麼這個情況將會在編譯時被發現,不需要顯示地表示該介面是否實作了這個介面。你可以使用Go的反射實現這種情況,這會引起運行時錯誤,但無論怎樣,‘implements’關鍵字聲明起不了任何作用。
執行緒和佇列
Go語言內建了執行緒和佇列。它們被稱為協程和通道。要啟動一個協程,你只需要編寫go函數call(),該函數將在另一個執行緒中啟動。儘管Go標準庫中有鎖住「物件」的方法或函數,但本地多執行緒程式設計卻是使用的通道。通道在Go中是一個內建類型,該內建類型是其他任何類型的固定大小的先進先出通道。你可以將一個值壓入通道中,協程可以從通道裡面拉取這個值。如果通道滿了,壓入會阻塞;在通道是空的情況下,拉取則會阻塞。
Go中有錯誤沒異常
Go其實有異常處理但缺少不是像Java中那樣使用的。異常被稱作‘panic’,在程式碼中有一些真正的慌亂狀態時使用。從Java的規則來看,‘panic’類似於一些以‘…Error’結尾的異常。當這兒有某個異常的例子或某個錯誤可以被處理,這種狀態會透過系統呼叫返回,應用的函數預期以類似的模式處這種狀態。
沒有finally,defer取而代之
緊密耦合異常處理是Java與try/catch/finally特徵一起實現的特徵。在Java中你可以將無論如何都會執行的程式碼在finally程式碼區塊中。 Go提供了關鍵字‘defer’讓你指定一個在方法返回前(即使方法有panic)調用的函數。使用Defer來解決上述問題的方案使得你更不容易濫用。你不能在deferred一個函數呼叫後寫任何可執行的程式碼。但在Java中,你甚至可以在finally區塊中寫回傳聲明,或者看見非常混亂的try語句用於處理finally區塊中要執行的程式碼也可能會拋出異常的情況。 Go傾向於前者。
總的來說,Go是一門有意思的語言。它不是Java的替代品,甚至在語言層面也不是。 Java和Go不是為同類型的任務提供服務-Java是企業級開發語言,Go是系統級程式語言。
推薦java影片教學:JAVA影片教學
推薦go影片教學:go影片教學
########以上是php轉go還是java呢?的詳細內容。更多資訊請關注PHP中文網其他相關文章!