{
  "assessmentTests": {
    "java_test": {
      "name": "Java 測驗",
      "desc": "30 道關於核心語法、物件導向、集合、泛型、異常和併發的情景題 — 判斷你對 Java 的理解是否與職位要求的 Java 工作能力相符。",
      "recommendation": "你的 Java 技能概覽",
      "results": {
        "beginner": {
          "name": "初級",
          "desc": "你能寫出工作的類和方法，但你錯的題往往聚焦在恆等性和預設值而不是語法 — String 的 == 對比 .equals、為什麼 new String(\"x\") 永遠不會重用字串池、數值欄位預設值與包裝欄位預設值的區別。這都不是說你 Java 能力不行；這些是透過試錯而不是從引用和原始值在底層如何運作來學 Java 的人容易踩雷的特定規則。在工作中很重要，因為每一個這樣的坑都是程式碼編譯、執行，卻悄悄做錯事的地方。",
          "recommendation": "先集中學三樣東西，按這個順序：為什麼 == 在兩個 String 物件上比較引用而非字元（而 .equals 幾乎總是你想要的）、int 溢位如何悄悄換行而非拋異常、為什麼未初始化的 Integer 欄位預設值是 null，而 int 欄位預設值是 0。Oracle 官方 Java 教程和 Baeldung 都用可執行的例子講了這三個。"
        },
        "intermediate": {
          "name": "中級",
          "desc": "你日常應用程式碼寫得很順手 — 類、集合、直白的控制流 — 日常功能工作不會讓你放慢速度。從這裡到高級的差距主要在 Java 規則與併發和泛型互相作用時會發生什麼：一個用宣告型別而非期望物件的實際型別來解析的靜態方法、一個你悄悄依賴的 HashMap 迭代順序、一個從列表中間移除元素時丟擲的 ConcurrentModificationException。這些是透過眼神檢查能過的 bug，只有在特定執行時條件下才會顯露。",
          "recommendation": "專注編譯器對你程式碼的靜態檢視如何與執行時差異：過載解析和靜態方法被宣告型別而非執行時型別隱藏、為什麼 HashMap 不保證迭代順序、為什麼在迭代時直接修改列表丟擲 ConcurrentModificationException。然後學泛型擦除，因為這個絆倒已經分別知道集合框架的人。"
        },
        "advanced": {
          "name": "高級",
          "desc": "這是大多數職位招募資訊說的「懂 Java」的等級。你讀一個類有靜態塊、例項塊和多個建構子能預測它們的精確執行順序，你知道為什麼 finally 塊能悄悄丟棄 try 塊的返回值，你會選擇 try-with-resources 而不是手工 finally-close，因為你知道它給你的順序保證。把這個等級和頂級分開的是併發和介面等級工作的一側：synchronized 實際鎖什麼、volatile 做和不做什麼、預設方法衝突如何解決。",
          "recommendation": "深入那些保護其他執行緒和其他介面也要動的程式碼的部分：synchronized 例項方法鎖什麼 vs synchronized 靜態方法鎖什麼、為什麼 volatile 給可見性但不給 counter++ 的原子性、Java 如何強制你手工解決預設方法鑽石問題。Baeldung 和《Java Concurrency in Practice》關於 Java Memory Model 的資料是這兩者的下一步。"
        },
        "expert": {
          "name": "專家",
          "desc": "你在每一部分都拿了高分 — 核心語法和型別、物件導向和作用域、集合和泛型、異常、併發和習語。實際上這意味著你可以被扔進一個陌生人的類，解釋為什麼出現編譯錯誤、執行時異常或悄悄錯的值，而不只是語法說應該怎樣，後者才是更難、更有價值的技能。在這個等級，語言本身很少是限制因子；限制通常來自併發設計或底層資料的形狀。",
          "recommendation": "收益現在來自設計和診斷：讀一個執行緒轉儲而不是假設死鎖、在 synchronized、java.util.concurrent 鎖和原子量之間選擇作為權衡而不是預設、stream 管道設計故意保持惰性而不是意外。如果你在因一個職位而被篩選，講一個像漏掉 happens-before 邊界或生產環境中找到的 ConcurrentModificationException 這樣的併發 bug，而不是數 Java 特性 — 這展示的是你的推理能力，而不只是詞彙。"
        }
      },
      "questions": [
        {
          "question": "你建立兩個 String 物件：String a = new String(\"cat\"); String b = new String(\"cat\"); a == b 計算為什麼？",
          "options": [
            {
              "icon": "",
              "label": "true"
            },
            {
              "icon": "",
              "label": "取決於 JVM 的字串池設定"
            },
            {
              "icon": "",
              "label": "出現編譯錯誤"
            },
            {
              "icon": "",
              "label": "false"
            }
          ]
        },
        {
          "question": "Integer x = 100; Integer y = 100; System.out.println(x == y); 然後 Integer x2 = 200; Integer y2 = 200; System.out.println(x2 == y2); 這兩行列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "true 然後 true"
            },
            {
              "icon": "",
              "label": "false 然後 false"
            },
            {
              "icon": "",
              "label": "無法編譯"
            },
            {
              "icon": "",
              "label": "true 然後 false"
            }
          ]
        },
        {
          "question": "int max = Integer.MAX_VALUE; System.out.println(max + 1); 會發生什麼？",
          "options": [
            {
              "icon": "",
              "label": "丟擲 ArithmeticException"
            },
            {
              "icon": "",
              "label": "再次列印 Integer.MAX_VALUE"
            },
            {
              "icon": "",
              "label": "列印 Integer.MIN_VALUE"
            },
            {
              "icon": "",
              "label": "編譯錯誤"
            }
          ]
        },
        {
          "question": "System.out.println(0.1 + 0.2 == 0.3); 這列印什麼，為什麼？",
          "options": [
            {
              "icon": "",
              "label": "false，因為 0.1 和 0.2 在二進位制浮點數中無法精確表示"
            },
            {
              "icon": "",
              "label": "true，因為 Java 會把 double 之和舍入到最接近的小數"
            },
            {
              "icon": "",
              "label": "true，因為兩位小數在 double 中相加是精確的"
            },
            {
              "icon": "",
              "label": "因比較不精確而丟擲 ArithmeticException"
            }
          ]
        },
        {
          "question": "一個類宣告兩個例項欄位無初始化器：int count; 和 Integer total; 建構子執行前，它們的預設值是什麼？",
          "options": [
            {
              "icon": "",
              "label": "count 和 total 都是 0"
            },
            {
              "icon": "",
              "label": "count 和 total 在賦值之前都沒有值"
            },
            {
              "icon": "",
              "label": "count 是 0 而 total 是 null"
            },
            {
              "icon": "",
              "label": "count 和 total 都是 null"
            }
          ]
        },
        {
          "question": "一個迴圈執行 1000 次，每次都在 String result 上執行 result += \"x\";。底層實際發生什麼？",
          "options": [
            {
              "icon": "",
              "label": "原有 String 的字元陣列被原地擴充套件"
            },
            {
              "icon": "",
              "label": "Java 把所有拼接合併成一個最終的 String"
            },
            {
              "icon": "",
              "label": "所有 1000 次迭代共用一個 StringBuilder"
            },
            {
              "icon": "",
              "label": "建立一個新的 String 並賦值給 result"
            }
          ]
        },
        {
          "question": "final List<String> names = new ArrayList<>(); 以下哪個為真？",
          "options": [
            {
              "icon": "",
              "label": "names.add(\"Ana\") 能編譯並執行"
            },
            {
              "icon": "",
              "label": "names.add(\"Ana\") 無法編譯"
            },
            {
              "icon": "",
              "label": "該列表可以安全地進行併發寫入"
            },
            {
              "icon": "",
              "label": "final 對區域變數沒有任何作用"
            }
          ]
        },
        {
          "question": "int[] a = {1, 2, 3}; int[] b = {1, 2, 3}; System.out.println(a == b); System.out.println(Arrays.equals(a, b)); 這兩行列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "false 然後 true"
            },
            {
              "icon": "",
              "label": "true 然後 true"
            },
            {
              "icon": "",
              "label": "false 然後 false"
            },
            {
              "icon": "",
              "label": "無法編譯"
            }
          ]
        },
        {
          "question": "void show(Object o) { print(\"Object\"); } void show(String s) { print(\"String\"); } Object ref = \"hello\"; show(ref); 哪個過載執行，為什麼？",
          "options": [
            {
              "icon": "",
              "label": "show(String)，因為物件的執行時類是 String"
            },
            {
              "icon": "",
              "label": "show(Object)，因為過載是按宣告型別選擇的"
            },
            {
              "icon": "",
              "label": "都不執行，該呼叫有歧義且無法編譯"
            },
            {
              "icon": "",
              "label": "兩個都執行，各一次，因為兩個過載都匹配"
            }
          ]
        },
        {
          "question": "類 Base 有 static void greet() { print(\"Base\"); }。類 Derived 繼承 Base 並也宣告 static void greet() { print(\"Derived\"); }。你寫：Base ref = new Derived(); ref.greet(); 列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "Derived"
            },
            {
              "icon": "",
              "label": "無法編譯"
            },
            {
              "icon": "",
              "label": "Base"
            },
            {
              "icon": "",
              "label": "先 Base，再 Derived"
            }
          ]
        },
        {
          "question": "在方法內，你寫 int count = 0; 然後嘗試從傳遞給另一方法的 lambda 內引用 count。為了編譯，count 必須滿足什麼？",
          "options": [
            {
              "icon": "",
              "label": "必須是 final 或事實上的 final"
            },
            {
              "icon": "",
              "label": "沒有任何要求，任何區域變數都行"
            },
            {
              "icon": "",
              "label": "必須用 volatile 關鍵字宣告"
            },
            {
              "icon": "",
              "label": "必須是類的欄位，而不是區域變數"
            }
          ]
        },
        {
          "question": "void rename(StringBuilder sb) { sb = new StringBuilder(\"new\"); } 被呼叫為 StringBuilder original = new StringBuilder(\"old\"); rename(original); original 呼叫後是什麼？",
          "options": [
            {
              "icon": "",
              "label": "變成了 \"new\""
            },
            {
              "icon": "",
              "label": "變成了 null"
            },
            {
              "icon": "",
              "label": "仍然是 \"old\""
            },
            {
              "icon": "",
              "label": "會丟擲一個執行時異常"
            }
          ]
        },
        {
          "question": "一個類有一個靜態初始化塊、一個例項初始化塊和一個建構子，源順序如此。你一個接一個建立這個類的兩個物件。這些以什麼順序執行？",
          "options": [
            {
              "icon": "",
              "label": "靜態塊執行一次，之後每個物件依次執行例項塊和建構子"
            },
            {
              "icon": "",
              "label": "對每個物件，三者都按原始碼順序執行"
            },
            {
              "icon": "",
              "label": "每個物件先執行建構子再執行例項塊，最後執行一次靜態塊"
            },
            {
              "icon": "",
              "label": "每建立一個物件都執行一次靜態塊，然後是例項塊，再是建構子"
            }
          ]
        },
        {
          "question": "一個類有 void log(String s) 和 void log(String... args)。你呼叫 log(\"hi\")。哪個執行？",
          "options": [
            {
              "icon": "",
              "label": "log(String... args)"
            },
            {
              "icon": "",
              "label": "編譯錯誤，呼叫存在歧義"
            },
            {
              "icon": "",
              "label": "log(String s)"
            },
            {
              "icon": "",
              "label": "先宣告的那個過載版本"
            }
          ]
        },
        {
          "question": "建構子的第一行呼叫 this(0); 委託給同一類中的另一個建構子。this() 允許出現在哪裡？",
          "options": [
            {
              "icon": "",
              "label": "在建構子返回之前的方法體內任何位置"
            },
            {
              "icon": "",
              "label": "只能作為建構子中的第一條語句"
            },
            {
              "icon": "",
              "label": "只能作為建構子的最後一條語句"
            },
            {
              "icon": "",
              "label": "只能在用委託關鍵字標記的建構子中"
            }
          ]
        },
        {
          "question": "你需要一個會在前端經常插入元素的列表，而隨機讀取很少。哪個是更好的結構擬合，為什麼？",
          "options": [
            {
              "icon": "",
              "label": "ArrayList，因為其底層陣列讓在頭部插入元素的速度最快"
            },
            {
              "icon": "",
              "label": "兩者都可以，因為它們都實現了 List，並提供相同的保證"
            },
            {
              "icon": "",
              "label": "LinkedList，因為頭部插入是 O(1) 而非 O(n)"
            },
            {
              "icon": "",
              "label": "LinkedList，因為它能提供 O(1) 的隨機訪問"
            }
          ]
        },
        {
          "question": "你按特定順序向一個普通 HashMap 插入五個條目，然後用 for-each 迴圈迭代它。條目以什麼順序出現？",
          "options": [
            {
              "icon": "",
              "label": "按插入順序"
            },
            {
              "icon": "",
              "label": "順序沒有保證"
            },
            {
              "icon": "",
              "label": "按鍵排序"
            },
            {
              "icon": "",
              "label": "按插入順序的逆序"
            }
          ]
        },
        {
          "question": "一個普通 java.util.HashMap 一次最多能持有多少個 null 鍵，多少個 null 值？",
          "options": [
            {
              "icon": "",
              "label": "不能有 null 鍵，也不能有 null 值"
            },
            {
              "icon": "",
              "label": "一個 null 鍵，任意數量的 null 值"
            },
            {
              "icon": "",
              "label": "null 鍵或 null 值都可以有任意多個"
            },
            {
              "icon": "",
              "label": "一個 null 鍵和一個 null 值"
            }
          ]
        },
        {
          "question": "你用 for-each 迴圈迭代一個 List，在迴圈體內直接對列表呼叫 list.remove(item)，在某些但非全部元素上。會發生什麼？",
          "options": [
            {
              "icon": "",
              "label": "恰好刪除預期的那些元素"
            },
            {
              "icon": "",
              "label": "會刪除，但要等迴圈結束後才生效"
            },
            {
              "icon": "",
              "label": "丟擲 IndexOutOfBoundsException"
            },
            {
              "icon": "",
              "label": "丟擲 ConcurrentModificationException"
            }
          ]
        },
        {
          "question": "在執行時，給定一個 List<String> list，你透過反射或 instanceof 實際能確定什麼關於它的泛型型別引數？",
          "options": [
            {
              "icon": "",
              "label": "list.getElementType() 返回 String.class"
            },
            {
              "icon": "",
              "label": "instanceof List<String> 會檢查元素型別"
            },
            {
              "icon": "",
              "label": "JVM 將其儲存為可透過 getGenericType() 讀取的後設資料"
            },
            {
              "icon": "",
              "label": "無法確定元素型別的任何資訊"
            }
          ]
        },
        {
          "question": "switch (day) { case 1: case 2: print(\"Weekday\"); break; case 6: print(\"Saturday\"); case 7: print(\"Sunday\"); break; default: print(\"?\"); } 如果 day 是 6，列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "只列印 Saturday"
            },
            {
              "icon": "",
              "label": "只列印 Sunday"
            },
            {
              "icon": "",
              "label": "Saturday，Sunday，然後是 ?"
            },
            {
              "icon": "",
              "label": "Saturday，然後 Sunday"
            }
          ]
        },
        {
          "question": "Product 類需要一個單個、顯然的「自然」按價格排序，加上在程式碼庫不同地方按名稱或庫存等級排序的能力。哪個組合是正確的設計？",
          "options": [
            {
              "icon": "",
              "label": "三次分別實現 Comparable<Product>"
            },
            {
              "icon": "",
              "label": "價格用 Comparable，名稱和庫存另用單獨的 Comparator"
            },
            {
              "icon": "",
              "label": "名稱用 Comparable，價格和庫存用 Comparator"
            },
            {
              "icon": "",
              "label": "一個 Comparable，帶三個過載的 compareTo 方法"
            }
          ]
        },
        {
          "question": "方法呼叫 new FileReader(path)，宣告 throws IOException。IOException 繼承 Exception 而非 RuntimeException。為了編譯你必須做什麼？",
          "options": [
            {
              "icon": "",
              "label": "什麼都不用做，照原樣就能編譯"
            },
            {
              "icon": "",
              "label": "捕獲 IOException 或宣告 throws IOException"
            },
            {
              "icon": "",
              "label": "在呼叫處捕獲 RuntimeException"
            },
            {
              "icon": "",
              "label": "將該方法宣告為 static"
            }
          ]
        },
        {
          "question": "try (Resource a = new Resource(\"A\"); Resource b = new Resource(\"B\")) { ... } 使用兩個實現 AutoCloseable 的資源。如果 try 塊正常結束，它們以什麼順序被關閉？",
          "options": [
            {
              "icon": "",
              "label": "按宣告順序，先 A 後 B"
            },
            {
              "icon": "",
              "label": "先 B，然後 A"
            },
            {
              "icon": "",
              "label": "兩者同時關閉"
            },
            {
              "icon": "",
              "label": "只有 B 會被自動關閉"
            }
          ]
        },
        {
          "question": "int getValue() { try { return 1; } finally { return 2; } } 呼叫 getValue() 返回什麼？",
          "options": [
            {
              "icon": "",
              "label": "1"
            },
            {
              "icon": "",
              "label": "丟擲異常"
            },
            {
              "icon": "",
              "label": "2"
            },
            {
              "icon": "",
              "label": "無法編譯"
            }
          ]
        },
        {
          "question": "try { ... } catch (IOException e) { ... } catch (FileNotFoundException e) { ...}，FileNotFoundException 繼承 IOException。編譯這個會怎樣？",
          "options": [
            {
              "icon": "",
              "label": "因第二個 catch 不可達而產生編譯錯誤"
            },
            {
              "icon": "",
              "label": "能編譯，由 FileNotFoundException 塊處理該型別"
            },
            {
              "icon": "",
              "label": "能編譯，兩個 catch 塊依次執行"
            },
            {
              "icon": "",
              "label": "能編譯，但執行時會因 FileNotFoundException 而失敗"
            }
          ]
        },
        {
          "question": "一個類有一個 synchronized 例項方法 process() 和一個 synchronized 靜態方法 configure()。具體每個鎖什麼？",
          "options": [
            {
              "icon": "",
              "label": "process() 鎖例項，configure() 鎖 Class 物件"
            },
            {
              "icon": "",
              "label": "兩者都鎖同一個 JVM 全域性鎖"
            },
            {
              "icon": "",
              "label": "process() 鎖 Class 物件，configure() 鎖呼叫者例項"
            },
            {
              "icon": "",
              "label": "內部沒有 synchronized 塊時，兩者都不鎖任何東西"
            }
          ]
        },
        {
          "question": "欄位被宣告為 volatile int counter = 0;，多個執行緒併發執行 counter++ 在它上面。volatile 在這裡防止丟失的更新嗎？",
          "options": [
            {
              "icon": "",
              "label": "能"
            },
            {
              "icon": "",
              "label": "不能"
            },
            {
              "icon": "",
              "label": "僅對 int 和 long 欄位有效"
            },
            {
              "icon": "",
              "label": "僅當該欄位也是 static 時"
            }
          ]
        },
        {
          "question": "介面 A 和介面 B 各宣告一個預設方法 describe()。一個類實現兩個都且不自己覆蓋 describe()。會怎樣？",
          "options": [
            {
              "icon": "",
              "label": "執行 A 的版本，因為 A 列在前面"
            },
            {
              "icon": "",
              "label": "兩個版本都會執行，一個接一個"
            },
            {
              "icon": "",
              "label": "可以編譯，但呼叫時會丟擲異常"
            },
            {
              "icon": "",
              "label": "編譯錯誤，除非類中重寫 describe()"
            }
          ]
        },
        {
          "question": "list.stream().filter(x -> x > 0).map(x -> x * 2); 被寫出但結果從未賦給像 .collect() 或 .forEach() 這樣的終端操作。這行執行時實際發生什麼？",
          "options": [
            {
              "icon": "",
              "label": "什麼都不發生，流管道從未執行"
            },
            {
              "icon": "",
              "label": "每個元素都會立即被過濾和對映"
            },
            {
              "icon": "",
              "label": "只有 filter 執行，map 要等待終端操作"
            },
            {
              "icon": "",
              "label": "丟擲 IllegalStateException"
            }
          ]
        }
      ],
      "optionOrderVersion": "9d7b97ef6cccf4e2"
    }
  },
  "testNames": {
    "java-test": "Java 技能"
  }
}
