Mối quan hệ giữa Any, AnyVal, AnyRef, Object và cách chúng ánh xạ khi được sử dụng trong mã Java?


111

Tôi thường thử mọi cách kết hợp cho đến khi nó được biên dịch. Ai đó có thể giải thích những gì tôi nên sử dụng ở đâu?

Câu trả lời:


125

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à 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.AnyAnyRefAnyVal

Đ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 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 AnyValScala. 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 AnyAnyRef, 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 Anyhay 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 đó fhsẽ tự động đóng hộp, nhưng gsẽ không. Điều đó hơi ngược lại với những gì Java làm, trong đó fhkhô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 AnyValhoặ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 AnyRefvà 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.


2
Bản cập nhật: kể từ Scala 2.9.2, AnyValđược định nghĩa là sealed trait AnyVal extends Any. Nhưng trong Scala 2.10 này đã thay đổi đến abstract class AnyVal extends Any with NotNull, và bây giờ có thể mở rộng AnyValvới các tính năng lớp giá trị mới, ví dụ như: class MyValue(val u: Int) extends AnyVal.
ebruchez

@ebruchez Cảm ơn bạn đã lưu ý. Tôi đã cập nhật câu trả lời của mình với tổng quan về các khả năng mới.
Daniel C. Sobral

Không có gì và Null liên quan đến điều này như thế nào?
Gaurav Khare


5

AnyAnyVal, 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ự Nothinglà 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 Objectsẽ mong đợi một tỷ lệ Any/ AnyRef.

Bạn thực sự đang cố gắng làm gì?


Tôi đang cố gắng hiểu chủ đề này tốt hơn để biết mình nên sử dụng loại nào khi định gọi Java là Scala hoặc ngược lại. Câu trả lời này stackoverflow.com/questions/2334200/… và dàn diễn viên của nó để AnyRefnhắc nhở tôi rằng điều này vẫn còn bí ẩn đối với tôi.
huynhjl 26/02/10
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.