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

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

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

-   語言環境
    
    相較於「應用程式」需要一個「作業系統」才能運行。這裡的「執行環境」(Runtime) 從概念上來說，就像是「程式語言」的「作業系統」一般，提供程式語言所需的一切基礎建設，並且幫我們把「中介碼」編譯成「機械碼」，讓應用程式得以運行在不同的 CPU 架構上。在 Java 與 .NET 都有這樣的機制。
    
    | Java 名詞 | .NET 名詞 |
    | --- | --- |
    | [JVM](https://zh.m.wikipedia.org/zh-tw/Java%E8%99%9A%E6%8B%9F%E6%9C%BA) (Java Virtual Machine) | [CLR](https://zh.wikipedia.org/wiki/%E9%80%9A%E7%94%A8%E8%AA%9E%E8%A8%80%E9%81%8B%E8%A1%8C%E5%BA%AB) (Common Language Runtime) |
    
-   軟體開發套件 (SDK)
    
    開發應用程式肯定需要許多開發時常見的工具與基礎建設，例如**編譯器**(Compiler)、**分析工具**(Analyzer)、**函式庫**(Libraries)、各種命令列工具等等，這些通稱為 Software Development Kit (SDK)。
    
    | Java 名詞 | .NET 名詞 |
    | --- | --- |
    | [JDK](https://zh.wikipedia.org/zh-tw/JDK) (Java Development Kit) | [.NET SDK](https://learn.microsoft.com/zh-tw/dotnet/core/sdk?WT.mc_id=DT-MVP-4015686) |
    
-   程式執行環境 (Runtime)
    
    如果你只是單純的想執行應用程式，只要安裝 Runtime 即可，不用安裝 SDK 軟體開發套件：
    
    | Java 名詞 | .NET 名詞 |
    | --- | --- |
    | [JRE](https://zh.wikipedia.org/zh-tw/JRE) (Java Runtime Environment) | [.NET Runtime](https://learn.microsoft.com/en-us/dotnet/core/introduction?WT.mc_id=DT-MVP-4015686) |
    
    我們要執行「應用程式」的時候，需要一個**宿主**(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` |
    
-   類別封裝
    
    我們可以用 `package` 或 `namespace` 對類別進行分類，但是 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](https://en.wikipedia.org/wiki/Bytecode) | [CIL bytecode](https://en.wikipedia.org/wiki/Common_Intermediate_Language) 或 IL code |
    
    > CIL = Common Intermediate Language
    
-   建置程式碼 (Build)
    
    如果要編譯單一原始碼檔案，使用 Java 簡單很多，使用 .NET 就會異常複雜，[微軟官方也說](https://github.com/dotnet/roslyn/issues/12393#issuecomment-233468174)不打算讓你這樣用！
    
    | Java | .NET |
    | --- | --- |
    | `javac myapp.java` | *沒人這樣用* |
    
    如果要編譯多個原始碼檔案 (完整專案或模組)，使用 JDK 就顯得複雜很多，而 .NET 就內建 MSBuild 讓你使用，整件事變的異常輕鬆！
    
    | Java | .NET |
    | --- | --- |
    | `javac @filelist -sourcepath src -d bin` | `dotnet build`  <br>(但你先要有 `*.csproj` 專案檔才行) |
    
    > 由於 JDK 並沒有內建好用的專案建置工具(Build Tool)，但是要「自製建置工具」其實還蠻簡單的，理論上你只要先把「檔案清單」收集好，任何 Java 專案你都能建置才對。然而大部分的 Java 開發者都會依賴開發工具內建的 Build Tool 來使用，不然就是使用 [Maven](https://maven.apache.org) 或 [Gradle](https://gradle.org/) 等建置工具。
    
-   專案範本 (Project Templates)
    
    .NET 在這方面做得相當好，而 Java 陣營的人主要還是靠開發工具提供此功能，或是 [Maven](https://maven.apache.org/) 也有提供
    
    | 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](https://www.oracle.com/tw/corporate/features/understanding-java-9-modules.html))，所做到的事情，就跟 .NET 的**專案**架構相當類似，但我認為 `JPMS` 更像是 .NET 的 [NuGet](https://nuget.org/) 套件，不過概念上確實沒辦法 100% 對應。
    
    你可以透過以下指令列出 JDK 內建的模組清單：
    
    ```bash
    java --list-modules
    ```
    
    其實「模組」本身就是個相當抽象的概念，在 Java 世界裡，不同的開發工具都有各自的「模組」定義，所以其實初學者很容易搞混這個概念。
    
    我以 IntelliJ IDEA 為例，在新增 Module 的時候，竟然就有 `5` 種不同概念。但其實你可以把他統合為一個簡單的概念，那就是**專案**！
    
    ![IntelliJ IDEA > Project Settings](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/a3fc3cdde580c0cfac72-187118783-7d80e47f-4f0b-4fdd-a27b-7d124506f396.png)
    
    我們一個 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](https://www.jetbrains.com/help/idea/facet-page.html) 則是快速加入一個 Framework (框架) 功能，這個功能的背後，其實也只是幫你加入 `Modules` 或 `Libraries` 而已，有點類似 Visual Studio 2022 裡面 `Manage NuGet Packages` 的安裝 NuGet 套件功能，因為 .NET 在新增 NuGet 套件的時候，也能自動調整**目錄結構**與**設定檔內容**，因此功能相當類似。
    

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

### 相關連結

-   [Understanding Java 9 Modules](https://www.oracle.com/tw/corporate/features/understanding-java-9-modules.html) / [理解 Java 9 的模組](https://medium.com/java-magazine-translation/%E7%90%86%E8%A7%A3-java-9-%E7%9A%84%E6%A8%A1%E7%B5%84-4aa30e1c7df9)
-   [What is JVM (Java Virtual Machine): Architecture Explained!](https://www.guru99.com/java-virtual-machine-jvm.html)
