Каковы отношения между Any, AnyVal, AnyRef, Object и как они отображаются при использовании в коде Java?


111

Обычно я пробую каждую комбинацию, пока она не скомпилируется. Может кто-нибудь объяснить, что я должен использовать и где?

Ответы:


125

Я не согласен с ответом Криса в одном отношении. Классы , и являютсяAnyAnyRefAnyVal классами. Но они не отображаются как классы в байт-коде из-за внутренних ограничений JVM.

Это происходит из-за того, что не все в Java является объектом. Помимо объектов есть примитивы. Все объекты в Java являются потомками java.lang.Object, но примитивы отделены друг от друга и в настоящее время * не могут быть расширены программистом. Также обратите внимание, что примитивы имеют «операторы», а не методы.

В Scala, с другой стороны, все является объектом, все объекты принадлежат классу и взаимодействуют между собой через методы. Сгенерированный байт-код JVM не отражает этого, но это не делает их менее значимыми, так же как в Java есть дженерики, даже если в байт-коде их нет.

Итак, в Scala все объекты являются потомками Any , и это включает как то, что Java считает объектами, так и то, что Java считает примитивами. В Java нет эквивалента, потому что нет такой унификации.

Все, что считается примитивом в Java, происходит от AnyValScala. До Scala 2.10.0 AnyValбыл закрыт, и программисты не могли его расширить. Было бы интересно посмотреть, что произойдет со Scala в .Net, поскольку одна только совместимость требует от Scala, по крайней мере, распознавания определяемых пользователем «примитивов».

Также расширение Anyis AnyRef, что эквивалентно java.lang.Object(по крайней мере, на JVM).

До Scala 2.9.x, пользователь не может расширить Anyили AnyVal, не ссылаться на них из Java, но были и другие виды использования они могут быть помещены в Scala. В частности, подписи типа:

def f(x: AnyVal) = println(x)
def g(x: AnyRef) = println(x)
def h(x: Any) = println(x)

То, что каждый из них означает, должно быть очевидно из иерархии классов. Следует, однако, отметить, что автоматическая упаковка fи hбудет, но gне будет. Это немного противоположно тому, что делает Java, в этом fи hне может быть указано, и g(определено с помощью java.lang.Object) вызовет автоматическую упаковку.

Однако, начиная с Scala 2.10.0, пользователь может расширить AnyValor Anyсо следующей семантикой:

  • Если класс расширяется AnyVal, при определенных условиях для него в куче не создается экземпляр. Это означает, что поля этого класса (в 2.10.0 разрешено только одно поле - изменится ли это, еще неизвестно) будут оставаться в стеке, независимо от того, являются ли они примитивами или ссылками на другие объекты. Это позволяет использовать методы расширения без затрат на создание экземпляра.

  • Если признак расширяется Any, то его можно использовать как с расширяющими, так AnyRefи с расширяющими классами AnyVal.

PS: На мой взгляд, Java, вероятно, последует за C # в разрешении "структурных" примитивов и, возможно, определений типов, поскольку параллелизм без обращения к ним оказывается трудным для достижения с хорошей производительностью.


2
Обновление: начиная с Scala 2.9.2, AnyValопределяется как sealed trait AnyVal extends Any. Но в Scala 2.10 это изменилось с abstract class AnyVal extends Any with NotNull, и теперь можно расширить AnyValс помощью новой функции классов значений, например: class MyValue(val u: Int) extends AnyVal.
ebruchez

@ebruchez Спасибо за замечание. Я обновил свой ответ обзором новых возможностей.
Дэниел С. Собрал

Какое отношение к этому имеет Nothing and Null?
Gaurav Khare


5

Anyи AnyVal, как я полагаю, являются частью системы типов Scala и не являются классами как таковыми (точно так же, Nothingкак тип, а не класс). Вы не можете использовать их явно из кода Java.

Однако при взаимодействии Java / Scala метод, принимающий Java, Objectбудет ожидать scala Any/ AnyRef.

Что вы на самом деле пытаетесь сделать?


Я пытаюсь лучше понять эту тему, чтобы знать, какой тип мне следует использовать, когда я планирую использовать Java для вызова Scala или наоборот. Этот ответ stackoverflow.com/questions/2334200/… и его приведение AnyRefпросто напомнили мне, что это все еще было для меня загадкой.
huynhjl,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.