Câu trả lời:
Tôi không đồng ý với câu trả lời của Chris ở một khía cạnh. Các lớp học , và là các lớp học. Nhưng chúng không xuất hiện dưới dạng các lớp trong bytecode, vì những hạn chế nội tại của JVM.Any
AnyRef
AnyVal
Điều này xuất phát từ thực tế là không phải mọi thứ trong Java đều là một đối tượng. Ngoài các đối tượng, có các nguyên thủy. Tất cả các đối tượng trong Java đều là hậu duệ của java.lang.Object
, nhưng các đối tượng nguyên thủy được đặt riêng biệt và hiện tại là * , không thể mở rộng bởi một lập trình viên. Cũng lưu ý rằng các nguyên thủy có "toán tử", không phải phương thức.
Mặt khác, trong Scala, mọi thứ đều là một đối tượng, tất cả các đối tượng đều thuộc về một lớp và chúng tương tác thông qua các phương thức. Bytecode của JVM được tạo ra không phản ánh điều này, nhưng điều đó không làm cho chúng kém đi chút nào, cũng giống như Java có các generics, mặc dù bytecode không có chúng.
Vì vậy, trong Scala, tất cả các đối tượng đều là hậu duệ của nó Any
, và điều đó bao gồm cả những gì Java coi là đối tượng và những gì Java coi là nguyên thủy. Không có tương đương trong Java vì không có sự thống nhất như vậy.
Mọi thứ được coi là nguyên thủy trong Java đều là hậu duệ của AnyVal
Scala. Cho đến khi Scala 2.10.0, AnyVal
đã bị niêm phong và các lập trình viên không thể mở rộng nó. Sẽ rất thú vị khi xem điều gì sẽ xảy ra với Scala trên .Net, vì chỉ riêng khả năng tương tác đã gọi cho Scala ít nhất phải nhận ra "nguyên thủy" do người dùng xác định.
Cũng mở rộng Any
là AnyRef
, tương đương với java.lang.Object
(trên JVM ở bất kỳ tỷ lệ nào).
Lên đến Scala 2.9.x, người dùng không thể mở rộng Any
hay AnyVal
, và cũng không tham khảo chúng từ Java, nhưng có những công dụng khác mà họ có thể được đưa vào trong Scala. Cụ thể, gõ chữ ký:
def f(x: AnyVal) = println(x)
def g(x: AnyRef) = println(x)
def h(x: Any) = println(x)
Ý nghĩa của mỗi phương tiện phải rõ ràng từ hệ thống phân cấp lớp. Tuy nhiên, lưu ý là điều đó f
và h
sẽ tự động đóng hộp, nhưng g
sẽ không. Điều đó hơi ngược lại với những gì Java làm, trong đó f
và h
không thể được chỉ định, và g
(được định nghĩa bằng java.lang.Object
) sẽ gây ra tự động đóng hộp.
Tuy nhiên, bắt đầu với Scala 2.10.0, người dùng có thể mở rộng AnyVal
hoặc Any
, với ngữ nghĩa sau:
Nếu một lớp mở rộng AnyVal
, sẽ không có cá thể nào được tạo cho nó trên heap trong các điều kiện nhất định. Điều này có nghĩa là các trường của lớp này (trên 2.10.0 chỉ cho phép một trường duy nhất - cho dù điều đó có thay đổi hay không) sẽ ở trên ngăn xếp, cho dù chúng là nguyên thủy hay tham chiếu đến các đối tượng khác. Điều này cho phép các phương pháp mở rộng mà không cần chi phí khởi tạo.
Nếu một đặc điểm mở rộng Any
, thì nó có thể được sử dụng với cả các lớp kéo dài AnyRef
và các lớp kéo dài AnyVal
.
PS: Theo quan điểm của riêng tôi, Java có khả năng đi theo C # trong việc cho phép các nguyên thủy "struct", và có thể là typedef, vì tính song song mà không sử dụng đến chúng đang tỏ ra khó thực hiện với hiệu suất tốt.
Xem cái này đi? Văn bản của trang có một số nhận xét về khả năng tương tác java. http://www.scala-lang.org/node/128
Any
và AnyVal
, tôi tin rằng, là một phần của hệ thống kiểu scala và không phải là các lớp như vậy (theo cách tương tự Nothing
là một kiểu, không phải một lớp). Bạn không thể sử dụng chúng một cách rõ ràng từ bên trong mã Java.
Howwever, trong tương tác Java / Scala, một phương thức chấp nhận Java Object
sẽ mong đợi một tỷ lệ Any
/ AnyRef
.
Bạn thực sự đang cố gắng làm gì?
AnyRef
nhắc nhở tôi rằng điều này vẫn còn bí ẩn đối với tôi.
AnyVal
được định nghĩa làsealed trait AnyVal extends Any
. Nhưng trong Scala 2.10 này đã thay đổi đếnabstract class AnyVal extends Any with NotNull
, và bây giờ có thể mở rộngAnyVal
với các tính năng lớp giá trị mới, ví dụ như:class MyValue(val u: Int) extends AnyVal
.