Trong ngôn ngữ lập trình Scala, mọi lớp đều kế thừa từ một gốc chung duy nhất là Any. Cấu trúc phân cấp này đảm bảo tính nhất quán giữa các kiểu dữ liệu nguyên thủy và các đối tượng phức tạp.
Lớp cơ sở Any
Vì Any là lớp cha của tất cả các lớp khác, mọi đối tượng trong Scala đều sở hữu các phương thức cơ bản như ==, !=, equals, hashCode và toString.
Đáng chú ý, các phương thức so sánh == và != trong Scala được khai báo là final, nghĩa là bạn không thể ghi đè chúng trong các lớp con. Trên thực tế, == sẽ gọi phương thức equals, còn != là phủ định của equals. Do đó, để thay đổi logic so sánh, lập trình viên chỉ cần ghi đè phương thức equals.
Hệ thống phân cấp của Scala chia thành hai nhánh chính từ Any: AnyVal và AnyRef.
Nhánh AnyVal (Value Types)
AnyVal là lớp cha của 9 kiểu giá trị được xây dựng sẵn: Byte, Short, Char, Int, Long, Float, Double, Boolean và Unit.
Tám kiểu đầu tiên tương ứng trực tiếp với các kiểu dữ liệu nguyên thủy trong Java và được biểu diễn dưới dạng các giá trị literal (hằng số). Kiểu Unit tương đương với void trong Java, đại diện cho việc phương thức không trả về kết quả có ý nghĩa, và nó chỉ có một thực thể duy nhất là ().
val code = 200
println(code.toString) // Kết quả: "200"
println(code.hashCode) // Kết quả: 200
Các kiểu giá trị này không thể khởi tạo bằng từ khóa new. Tuy nhiên, Scala cung cấp các chức năng mở rộng cho chúng thông qua cơ chế chuyển đổi ngầm định (implicit conversion). Ví dụ, các phương thức như max, min, hay to thực tế được định nghĩa trong lớp scala.runtime.RichInt.
val topValue = 10 max 20 // Trả về 20
val steps = 1 until 10 // Tạo Range từ 1 đến 9
val positiveValue = (-15).abs // Trả về 15
Mối quan hệ giữa các kiểu giá trị là "phẳng", nhưng Scala hỗ trợ tự động mở rộng kiểu (widening). Ví dụ, một giá trị Int có thể tự động chuyển đổi thành Long khi cần thiết.
Nhánh AnyRef (Reference Types)
AnyRef là lớp cơ sở cho tất cả các kiểu tham chiếu trong Scala. Trong môi trường chạy trên JVM, AnyRef thực chất chỉ là một bí danh (alias) của lớp java.lang.Object. Tất cả các lớp do người dùng định nghĩa hoặc các lớp từ thư viện chuẩn Java đều thuộc nhánh này.
Các kiểu dữ liệu đặc biệt: Null và Nothing
Ở dưới cùng của hệ thống phân cấp là hai loại đặc biệt:
1. Null: Đây là lớp con của mọi kiểu thuộc nhánh AnyRef. Nó đại diện cho tham chiếu null. Tuy nhiên, Null không tương thích với các kiểu thuộc nhánh AnyVal. Bạn không thể gán null cho một biến kiểu Int hay Boolean.
2. Nothing: Đây là kiểu dữ liệu nằm ở đáy cùng của toàn bộ hệ thống phân cấp. Nothing là lớp con của tất cả các lớp khác (bao gồm cả AnyVal và AnyRef). Điều đặc biệt là không có bất kỳ thực thể nào thuộc kiểu Nothing. Nó thường được sử dụng để đánh dấu các điểm kết thúc bất thường của chương trình, chẳng hạn như ném ra một ngoại lệ.
def triggerError(reason: String): Nothing = {
throw new RuntimeException(reason)
}
def calculatePercentage(score: Int, total: Int): Int = {
if (total > 0) (score * 100) / total
else triggerError("Tổng số phải lớn hơn 0")
}
Nhờ tính chất Nothing là lớp con của mọi kiểu, hàm triggerError có thể được sử dụng ở bất kỳ đâu mà vẫn đảm bảo tính đúng đắn về kiểu dữ liệu của biểu thức.