The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

.NET 與 Java 常見技術名詞與抽象概念對照表

雖然 .NET (C#) 與 Java 是兩個不同的語言,但這兩個都是 OOP 物件導向程式架構,而且 Java 出現的比較早,我們在 .NET 裡面也經常看到很多 Java 的影子,所以其實有不少相似之處。這篇文章我打算整理一下最近的感受,把一些常見的技術名詞與抽象概念做一些對照,幫助想要成為「斜槓青年」的朋友入門。

底下有些抽象概念,必須同時寫過 .NET 與 Java 的人才能理解,但在「斜槓」的過程中知道這些差異是有幫助的。

  • 語言環境

    相較於「應用程式」需要一個「作業系統」才能運行。這裡的「執行環境」(Runtime) 從概念上來說,就像是「程式語言」的「作業系統」一般,提供程式語言所需的一切基礎建設,並且幫我們把「中介碼」編譯成「機械碼」,讓應用程式得以運行在不同的 CPU 架構上。在 Java 與 .NET 都有這樣的機制。

    Java 名詞 .NET 名詞
    JVM (Java Virtual Machine) CLR (Common Language Runtime)
  • 軟體開發套件 (SDK)

    開發應用程式肯定需要許多開發時常見的工具與基礎建設,例如編譯器(Compiler)、分析工具(Analyzer)、函式庫(Libraries)、各種命令列工具等等,這些通稱為 Software Development Kit (SDK)。

    Java 名詞 .NET 名詞
    JDK (Java Development Kit) .NET SDK
  • 程式執行環境 (Runtime)

    如果你只是單純的想執行應用程式,只要安裝 Runtime 即可,不用安裝 SDK 軟體開發套件:

    Java 名詞 .NET 名詞
    JRE (Java Runtime Environment) .NET Runtime

    我們要執行「應用程式」的時候,需要一個宿主(host)才能執行,例如跑 .NET 的時候,你需要先將 *.cs 編譯成 *.dll 檔,然後透過 dotnet 命令列工具來執行。而 Java 則需要先將 *.java 編譯成 *.class 檔,然後透過 java 命令列工具才執行。

    Java .NET
    java myapp.class dotnet myapp.dll
    java -jar myapp.jar dotnet myapp.dll
  • 共用類別庫

    無論 Java 或 .NET 都有相當豐富的內建 API 可用,這些 API 被分類成一個一個的名稱,在 Java 被稱為 package (套件),在 .NET 則被稱為 namespace (命名空間),你在任何一個類別中,必須先引入才能使用。

    類型 Java .NET
    類別庫名稱 JCL (Java Class Library) BCL (Base Class Library)
    宣告套件語法 package namespace
    引入套件語法 import using
  • 類別封裝

    我們可以用 packagenamespace 對類別進行分類,但是 Java 與 .NET 的封裝方法就有不小的差異了。

    Java .NET
    一個 package 對應到一個資料夾,該資料夾可以包含多個 *.java 原始檔 一個 namespace 可以放在專案中任意位置、宣告在任意檔案,沒有嚴格限制,因此重構時容易亂掉
    相同 package 下的類別可以存取在不同 *.java 原始檔中的任意 private 類別 相同 namespace 下的類別不可以存取在相同 namespace*.cs 原始檔中的任意 private 類別
    一個 *.java 原始檔中,可以有多個類別,但只能有一個 public 公開類別,限制較嚴格 一個 *.cs 原始檔中,可以有多個類別,也能有多個 public 公開類別
    一個 *.java 檔只能編譯成一個 *.class 類別檔 無此概念
    多個 *.class 類別檔通常會被封裝到一個 *.jar 檔中 無此概念
    多個 *.class 類別檔可以被放置在一個目錄下,並可透過 java 執行時使用 -classpath 指定其路徑 多個 *.dll 檔案可以跟應用程式放在相同目錄下,如果沒有放在相同目錄就會變的很麻煩

    多個 *.java 原始檔最終可以合併成一個 *.jar 檔,而多個 *.cs 檔最終會合併到一個 *.dll 檔案,所以若以最終的結果來看,*.dll 比較接近 *.jar 的封裝方式。

    由於 .NET 沒有類似 *.jar 檔的機制,通常多個 *.cs 原始檔會使用「專案」進行管理,且最終會編譯到一個 *.dll 檔案中。因此,Java 的 *.jar 最接近 .NET 的概念應該是 *.dll 檔。

    Java .NET 說明
    java myapp.java 無此用法 Java 11 開始允許不用預先編譯原始碼,可直接執行
    java myapp.class dotnet myapp.dll  
    java -jar myapp.jar dotnet myapp.dll  
  • 中介語言 (intermediary language)

    寫完程式之後,無論 Java 或 .NET 都會將原始碼編譯成 中介碼 (Bytecode) 型態,他其實是一種高階的組合語言或稱中介語言(intermediary language)。

    Java .NET
    Bytecode CIL bytecode 或 IL code

    CIL = Common Intermediate Language

  • 建置程式碼 (Build)

    如果要編譯單一原始碼檔案,使用 Java 簡單很多,使用 .NET 就會異常複雜,微軟官方也說不打算讓你這樣用!

    Java .NET
    javac myapp.java 沒人這樣用

    如果要編譯多個原始碼檔案 (完整專案或模組),使用 JDK 就顯得複雜很多,而 .NET 就內建 MSBuild 讓你使用,整件事變的異常輕鬆!

    Java .NET
    javac @filelist -sourcepath src -d bin dotnet build
    (但你先要有 *.csproj 專案檔才行)

    由於 JDK 並沒有內建好用的專案建置工具(Build Tool),但是要「自製建置工具」其實還蠻簡單的,理論上你只要先把「檔案清單」收集好,任何 Java 專案你都能建置才對。然而大部分的 Java 開發者都會依賴開發工具內建的 Build Tool 來使用,不然就是使用 MavenGradle 等建置工具。

  • 專案範本 (Project Templates)

    .NET 在這方面做得相當好,而 Java 陣營的人主要還是靠開發工具提供此功能,或是 Maven 也有提供

    Java .NET
    沒有這玩意 dotnet new -l
    沒有這玩意 dotnet new console -n c1

    如果用 Maven 的專案產生器 (archetype),可以參考以下範例,指令超長,完全沒有 DX 可言 😅

    mvn org.apache.maven.plugins:maven-archetype-plugin:3.1.2:generate -DarchetypeArtifactId="spring-boot-blank-archetype" -DarchetypeGroupId="am.ik.archetype" -DarchetypeVersion="1.0.6" -DgroupId="com.duotify" -DartifactId="demo2"

  • 專案與模組 (Projects and Modules)

    .NET 使用 專案 (Project) 這個名詞,代表一種比 *.dll 還高一個階層的封裝。而在 Visual Studio 開發工具下,多個專案還可以透過方案(Solution)進行管理。

    由於 Java 8 以前並沒有什麼 專案 的概念,但從 Java 9 新推出一個 模組 (Modules) 系統,簡稱 JPMS (Java 9 Platform Module System),所做到的事情,就跟 .NET 的專案架構相當類似,但我認為 JPMS 更像是 .NET 的 NuGet 套件,不過概念上確實沒辦法 100% 對應。

    你可以透過以下指令列出 JDK 內建的模組清單:

    java --list-modules
    

    其實「模組」本身就是個相當抽象的概念,在 Java 世界裡,不同的開發工具都有各自的「模組」定義,所以其實初學者很容易搞混這個概念。

    我以 IntelliJ IDEA 為例,在新增 Module 的時候,竟然就有 5 種不同概念。但其實你可以把他統合為一個簡單的概念,那就是專案

    IntelliJ IDEA > Project Settings

    我們一個 Repo 裡面,可以有多個 pom.xml 檔,代表多個不同的專案。然後你可以從另一個沒有使用 Build Tool 的資料夾(也可以當成一個專案看待),加入這個 pom.xml 當成參考來源,IntelliJ IDEA 就會自動幫你合併起來,建置的時候自動幫你加入 -classpath 參數,如此而已。

    IntelliJ IDEA 的 Add Modules 比較像是 VS2022 裡面的 Add Reference > Projects 功能。

    IntelliJ IDEA 的 Libraries 就比較像是 VS2022 裡面的 Add Reference > Assemblies 功能。

    IntelliJ IDEA 的 Facets 則是快速加入一個 Framework (框架) 功能,這個功能的背後,其實也只是幫你加入 ModulesLibraries 而已,有點類似 Visual Studio 2022 裡面 Manage NuGet Packages 的安裝 NuGet 套件功能,因為 .NET 在新增 NuGet 套件的時候,也能自動調整目錄結構設定檔內容,因此功能相當類似。

之後我會陸續補充 .NET 與 Java 之間的抽象概念差異到這篇文章。

相關連結