1. 類別宣告時的錯誤
缺少存取修飾詞(預設為 package-private)
在 Java 中,如果你沒有明確為類別指定存取修飾詞,該類別就只會在目前套件內可見。這稱為 package-private,或「預設存取層級」。例如:
// 檔案 Book.java
class Book {
String title;
}
此類別無法從其他套件使用。如果你希望類別在各處都可存取(對核心模型通常就是要這樣),請使用 public 修飾:
public class Book {
String title;
}
為什麼這很重要?
若忘了加上 public,之後你可能會很困惑,為什麼其他套件中的某個 Library 看不到你的類別。
類別名稱與檔名不一致
在 Java 中,含有類別的檔名必須與檔內的 public 類別名稱完全一致(包含大小寫)。例如:
// 檔案 Book.java
public class Book {
// ...
}
如果你把檔名取為 book.java(小寫開頭),或更糟的是 BooK.java,編譯器會報錯。這也是為什麼當你改了類別名稱卻忘了改檔名時,IDE 會一直對你發出警告。
宣告語法錯誤:遺漏大括號、方法與欄位位置錯誤
Java 是一門嚴格的語言。如果哪裡少了大括號,或不小心在一個方法裡宣告另一個方法(這在 Java 中是不允許的!),編譯器會立刻提醒你。
錯誤宣告範例:
public class User
String name; // 糟了!缺了類別的大括號
public void printName() {
System.out.println(name);
}
}
正確寫法:
public class User {
String name;
public void printName() {
System.out.println(name);
}
}
請記住:
- 所有欄位與方法都只能宣告在類別的大括號內。
- 方法之間不可互相巢狀(有些語言允許巢狀方法,但 Java 不行)。
2. 建立物件時的錯誤
在初始化之前嘗試使用物件(NullPointerException)
最常見的錯誤之一,就是嘗試使用尚未建立的物件。在 Java 中,參考型別的變數預設為 null。
範例:
User user;
System.out.println(user.name); // NullPointerException!
為什麼?
變數 user 已宣告但尚未初始化。當你嘗試存取欄位或方法時——就會得到 NPE(NullPointerException)。
正確作法:
User user = new User();
System.out.println(user.name); // 現在就沒問題了(如果欄位不是 null)
呼叫建構子時的錯誤(參數不匹配、沒有預設建構子)
如果類別只有帶參數的建構子,嘗試不帶參數建立物件就會導致編譯錯誤。
public class Book {
String title;
public Book(String title) {
this.title = title;
}
}
Book book = new Book(); // 錯誤!沒有無參數建構子
解決方案: 要嘛新增一個無參數建構子,要嘛在建立時總是傳入所需值:
Book book = new Book("Java 入門");
重複建立物件而非重複使用
有時候新手每次需要用到物件時都重新 new 一個,而不是重複使用已建立的實例。
Book book = new Book("Java 入門");
System.out.println(book.title);
book = new Book("Java 入門"); // 何必呢?先前已經有相同的物件了!
System.out.println(book.title);
這不是編譯錯誤,但屬於不佳的風格——你會遺失舊物件的參考並浪費額外記憶體。
3. 最佳實務:如何避免踩雷
務必明確標示存取修飾詞
別偷懶,該寫就寫上 public、private 或 protected——這不僅關乎安全性,也關乎程式碼的可讀性。IDE 當然會提示,但最好養成一開始就寫清楚的習慣。
範例:
public class User {
private String name;
// ...
}
注意類別命名
- 類別名稱使用大寫開頭,採用 CamelCase:Book、LibraryUser、BookManager。
- 檔名必須與類別名稱完全一致。
使用建構子初始化必填欄位
如果物件有一些欄位在建立時必須填好,請加上帶參數的建構子。這能在使用階段避免錯誤。
範例:
public class User {
private String name;
public User(String name) {
this.name = name;
}
}
現在就不能建立沒有名稱的 User——編譯器不會允許。
4. 實作所學:打造迷你應用程式「圖書館」
讓我們繼續擴充教學用的應用程式。假設我們有一個 Book 類別,以及一個管理書籍的 Library 類別。
正確的類別宣告範例
// 檔案 Book.java
public class Book {
private String title;
private String author;
// 帶參數的建構子
public Book(String title, String author) {
this.title = title;
this.author = author;
}
// Getter
public String getTitle() {
return title;
}
public String getAuthor() {
return author;
}
}
正確的物件建立範例
Book book = new Book("Java 入門", "John Doe");
System.out.println(book.getTitle() + " - " + book.getAuthor());
管理類別範例
// 檔案 Library.java
import java.util.ArrayList;
public class Library {
private ArrayList<Book> books = new ArrayList<>();
public void addBook(Book book) {
books.add(book);
}
public void printAllBooks() {
for (Book book : books) {
System.out.println(book.getTitle() + " - " + book.getAuthor());
}
}
}
在 main 中的使用
public class Main {
public static void main(String[] args) {
Library library = new Library();
Book book1 = new Book("Java 入門", "John Doe");
Book book2 = new Book("OOP 白話", "Ivan Ivanov");
library.addBook(book1);
library.addBook(book2);
library.printAllBooks();
}
}
5. 圖示與示意圖
示意圖:該把什麼放在哪裡?
+-----------------------------+
| Book.java |
|-----------------------------|
| public class Book { |
| private String title; | <--- 欄位(只能在類別內)
| ... |
| public Book(...) {...} | <--- 建構子(在類別內)
| public String getTitle()| <--- 方法(在類別內)
| } |
+-----------------------------+
+-----------------------------+
| Main.java |
|-----------------------------|
| public class Main { |
| public static void main |
| // 建立物件 |
| Book book = new Book|
| } |
+-----------------------------+
6. 常見錯誤解析
錯誤 1:類別名稱與檔案不一致
// 檔案:Libraryuser.java
public class LibraryUser { // 類別名稱的 U 是大寫,但檔名是小寫!
// ...
}
class LibraryUser is public, should be declared in a file named LibraryUser.java
錯誤 2:試圖使用未初始化的物件
Book book;
System.out.println(book.getTitle()); // NullPointerException!
錯誤 3:遺漏大括號
public class Book
private String title; // 欄位通常設為 private 以進行封裝
// ...
}
';' expected
錯誤 4:在方法內宣告方法
public class User {
public void printName() {
void sayHello() {
System.out.println("Hello!"); // 不能在方法內宣告方法!
}
}
}
illegal start of type
GO TO FULL VERSION