Odpowiedzi:
Pod jednym względem nie zgodzę się z odpowiedzią Chrisa . Klasy Any
, AnyRef
i AnyVal
są zajęcia. Ale nie pojawiają się one jako klasy w kodzie bajtowym z powodu wewnętrznych ograniczeń JVM.
Wynika to z faktu, że nie wszystko w Javie jest obiektem. Oprócz obiektów istnieją prymitywy. Wszystkie obiekty w Javie są potomkami java.lang.Object
, ale prymitywy są oddzielone i obecnie * nie mogą być rozszerzalne przez programistę. Zauważ również, że prymitywy mają „operatory”, a nie metody.
Z drugiej strony w Scali wszystko jest przedmiotem, wszystkie obiekty należą do klasy i oddziałują za pomocą metod. Wygenerowany kod bajtowy maszyny JVM nie odzwierciedla tego, ale to nie czyni go mniejszym, tak jak Java ma typy generyczne, nawet jeśli kod bajtowy ich nie ma.
Tak więc w Scali wszystkie obiekty są potomkami Any
, co obejmuje zarówno to, co Java uważa za obiekty, jak i to, co Java uważa za prymitywy. Nie ma odpowiednika w Javie, ponieważ nie ma takiej unifikacji.
Wszystko, co jest uważane za prymitywne w Javie, pochodzi od AnyVal
Scali. Do wersji 2.10.0 Scala AnyVal
była zapieczętowana i programiści nie mogli jej rozszerzyć. Powinno być interesujące zobaczyć, co się stanie ze Scalą w .Net, ponieważ sama interoperacyjność wymaga od Scali przynajmniej rozpoznawania „prymitywów” zdefiniowanych przez użytkownika.
Rozszerzanie Any
jest również AnyRef
równoznaczne z java.lang.Object
(w każdym razie w JVM).
Do Scala 2.9.x, użytkownik nie może wykraczać Any
ani AnyVal
, ani odwoływać się do nich z Java, ale tam były inne zastosowania mogą one być umieszczone w Scala. W szczególności wpisz podpisy:
def f(x: AnyVal) = println(x)
def g(x: AnyRef) = println(x)
def h(x: Any) = println(x)
To, co każdy oznacza, powinno być oczywiste z hierarchii klas. Warto jednak zauważyć, że jest to f
i h
będzie automatyczne, ale g
nie będzie. Jest to trochę przeciwieństwo tego, co robi Java, f
i h
nie można go określić, a g
(zdefiniowane za pomocą java.lang.Object
) spowodowałoby automatyczne boksowanie.
Począwszy od Scali 2.10.0, użytkownik może jednak rozszerzyć AnyVal
lub Any
, stosując następującą semantykę:
Jeśli klasa się rozszerzy AnyVal
, w określonych warunkach nie zostanie dla niej utworzona żadna instancja na stercie. Oznacza to, że pola tej klasy (w wersji 2.10.0 dozwolone jest tylko jedno pole - okaże się, czy to się zmieni) pozostaną na stosie, niezależnie od tego, czy są to prymitywy, czy odniesienia do innych obiektów. Umożliwia to stosowanie metod rozszerzających bez ponoszenia kosztów tworzenia instancji.
Jeśli cecha się rozszerza Any
, może być używana zarówno z klasami, które rozszerzają, jak AnyRef
i klasami, które rozszerzają AnyVal
.
PS: Moim zdaniem Java prawdopodobnie podąży za C #, zezwalając na prymitywy "struct" i być może typyef, ponieważ paralelizm bez uciekania się do nich okazuje się trudny do osiągnięcia przy dobrej wydajności.
Widzieć to? W tekście strony znajdują się uwagi dotyczące współdziałania języka Java. http://www.scala-lang.org/node/128
Any
i AnyVal
są, jak sądzę, częścią systemu typów scala i nie są klasami jako takimi (w ten sam sposób, że Nothing
jest to typ, a nie klasa). Nie można ich używać jawnie z poziomu kodu Java.
Jednak w przypadku współdziałania Java / Scala metoda akceptująca Javę Object
będzie oczekiwać pliku scala Any
/ AnyRef
.
Co właściwie próbujesz zrobić?
AnyRef
przypomniała mi, że to wciąż jest dla mnie tajemnicze.
AnyVal
jest zdefiniowana jakosealed trait AnyVal extends Any
. Jednak w Scali 2.10 zmieniło się to naabstract class AnyVal extends Any with NotNull
i można teraz rozszerzyćAnyVal
o nową funkcję klas wartości, npclass MyValue(val u: Int) extends AnyVal
. : .