Ответы:
Я не согласен с ответом Криса в одном отношении. Классы , и являютсяAny
AnyRef
AnyVal
классами. Но они не отображаются как классы в байт-коде из-за внутренних ограничений JVM.
Это происходит из-за того, что не все в Java является объектом. Помимо объектов есть примитивы. Все объекты в Java являются потомками java.lang.Object
, но примитивы отделены друг от друга и в настоящее время * не могут быть расширены программистом. Также обратите внимание, что примитивы имеют «операторы», а не методы.
В Scala, с другой стороны, все является объектом, все объекты принадлежат классу и взаимодействуют между собой через методы. Сгенерированный байт-код JVM не отражает этого, но это не делает их менее значимыми, так же как в Java есть дженерики, даже если в байт-коде их нет.
Итак, в Scala все объекты являются потомками Any
, и это включает как то, что Java считает объектами, так и то, что Java считает примитивами. В Java нет эквивалента, потому что нет такой унификации.
Все, что считается примитивом в Java, происходит от AnyVal
Scala. До Scala 2.10.0 AnyVal
был закрыт, и программисты не могли его расширить. Было бы интересно посмотреть, что произойдет со Scala в .Net, поскольку одна только совместимость требует от Scala, по крайней мере, распознавания определяемых пользователем «примитивов».
Также расширение Any
is 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, пользователь может расширить AnyVal
or Any
со следующей семантикой:
Если класс расширяется AnyVal
, при определенных условиях для него в куче не создается экземпляр. Это означает, что поля этого класса (в 2.10.0 разрешено только одно поле - изменится ли это, еще неизвестно) будут оставаться в стеке, независимо от того, являются ли они примитивами или ссылками на другие объекты. Это позволяет использовать методы расширения без затрат на создание экземпляра.
Если признак расширяется Any
, то его можно использовать как с расширяющими, так AnyRef
и с расширяющими классами AnyVal
.
PS: На мой взгляд, Java, вероятно, последует за C # в разрешении "структурных" примитивов и, возможно, определений типов, поскольку параллелизм без обращения к ним оказывается трудным для достижения с хорошей производительностью.
Это видели? В тексте страницы есть некоторые замечания о совместимости Java. http://www.scala-lang.org/node/128
Any
и AnyVal
, как я полагаю, являются частью системы типов Scala и не являются классами как таковыми (точно так же, Nothing
как тип, а не класс). Вы не можете использовать их явно из кода Java.
Однако при взаимодействии Java / Scala метод, принимающий Java, Object
будет ожидать scala Any
/ AnyRef
.
Что вы на самом деле пытаетесь сделать?
AnyRef
просто напомнили мне, что это все еще было для меня загадкой.
AnyVal
определяется какsealed trait AnyVal extends Any
. Но в Scala 2.10 это изменилось сabstract class AnyVal extends Any with NotNull
, и теперь можно расширитьAnyVal
с помощью новой функции классов значений, например:class MyValue(val u: Int) extends AnyVal
.