Подтвердить что ты не робот

Если Int не может быть нулевым, что означает значение null.asInstanceOf [Int]?

В качестве теста я написал этот код:

object Ambig extends App {
  def f( x:Int    ) { println("Int"   ) }
  def f( x:String ) { println("String") }
  f( null.asInstanceOf[Int   ] )
  f( null.asInstanceOf[String] )
  f(null)
}

Я ожидал получить ошибку при последнем вызове функции f(), сказав, что это было неоднозначно. Компилятор принял его и произвел этот вывод:

Int
String
String

Теперь я предполагаю, что это связано с тем, что Int не является AnyRef, поэтому единственная версия f, которая работает для f (null), является f (x: String). Но тогда, если Int не может быть нулевым, что означает значение null.asInstanceOf [Int]? Repl говорит это типа Int:

scala> :type null.asInstanceOf[Int]
Int

но я действительно не вижу, как это работает. В конце концов, если я попытаюсь применить String к Int, все ад сломается:

scala> "foo".asInstanceOf[Int]
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source)
        ...

Конечно, что можно ожидать - "foo" нельзя превратить в Int. Но ни один из них не может быть нулевым, поэтому почему кастинг null в Int работает? Предположительно бокс в той или иной форме, но тип все еще Int, который не может быть нулевым...

Что мне не хватает?

4b9b3361

Ответ 1

Поведение отбрасывания null к Int зависит от контекста, в котором он выполняется.

Прежде всего, если вы добавили null в Int, это на самом деле означает целое число в штучной упаковке, значение которого null. Если вы помещаете выражение в контекст, где ожидаемый тип Any (который переводится в Object за сценой, потому что в байт-коде JVM нет способа ссылаться на примитивный тип и ссылочный тип с то эта ссылка), то это значение больше не преобразуется - поэтому println(null.asInstanceOf[Int]) печатает null.

Однако, если вы используете это одно целое число в квадрате в контексте, где ожидается примитив Int (Java Int), он будет преобразован в примитив, а null (в качестве значения по умолчанию для ссылочные типы), преобразованные в 0 (значение по умолчанию для примитивных типов).

Если общий метод делает это, то, естественно, вы получаете null назад.

Однако, если этот метод является специализированным, то его возвращаемый тип Int (который в этом случае является примитивным целым), поэтому значение null: Any должно быть преобразовано в примитив, как и раньше.

Следовательно, запуск:

object Test extends App {
  println(null.asInstanceOf[Int])

  def printit(x: Int) = println(x)

  printit(null.asInstanceOf[Int])

  def nullint[T] = null.asInstanceOf[T]

  println(nullint[Int])

  def nullspecint[@specialized(Int) T] = null.asInstanceOf[T]

  println(nullspecint[Int])
}

дает:

null
0
null
0

Ответ 2

Здесь вещь: asInstanceOf не имеет смысла. То, что этот метод делает, это сказать компилятору STOP MAKING SENSE и доверять тому, что вы говорите.

Теперь, если вы хотите знать, почему он возвращает 0, это потому, что asInstanceOf работает на AnyRef, а не на AnyVal. При применении к AnyVal вместо этого он будет использовать версию в коробке, а в коробке null будет значение 0.

Ответ 3

Похоже, он просто автоматически преобразует его в ноль:

scala> null.asInstanceOf[Int]
res0: Int = 0

И, конечно, 0, в отличие от нуля, может быть Int.

Ответ 4

Во-первых, мы все согласны с тем, что мы не можем назначить null на scala.Int, как описано в http://www.scala-lang.org/api/current/index.html#scala.Null

Во-вторых, почему, когда мы делаем println(null.asInstanceOf[Int]), он дает null?
Это происходит из-за реализации println. В итоге он вызывает метод java String.valueOf, который

return (obj == null) ? "null" : obj.toString();

Если вы выполните null.asInstanceOf[Int] == null в оболочке, он вернет true, но дает противоположное предупреждение о том, что "сравнение значений типов Int и Null с использованием` == 'всегда будет давать false". Я думаю, что это может быть проблемой в стирании типа scala.

Выполнение println требует только scala. Любой тип, поэтому кастинг null.asInstanceOf[Int] на самом деле еще не произошел. Поэтому нам просто нужно помнить, что когда вы назначаете null.asInstanceOf[Int] Int, приведение происходит во время выполнения на основе семантики стирания scala и присваивает ему 0.

Кстати, вы все равно можете сделать f (null) без какой-либо ошибки компиляции, потому что scala делает неявное преобразование для вас

 null -> java.lang.Integer -> scala.Int

Однако вы увидите, что он взрывается во время выполнения.