本文介绍了无法在Kotlin中将java.lang.Integer强制转换为java.lang.Long(初始值为null时)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我符合以下条件,则可以正常使用(即编号分配为1000)

If I have the following, it works (i.e. number get assign 1000)

fun main(args: Array<String>) {
    var number: Long ? = null // or number = 0
    val simpleObject = SimpleClass()
    number = 1000
    println("Hi + $number")
}

如果我符合以下条件,则可以正常使用(即编号分配为1000)

If I have the following, it works (i.e. number get assign 1000)

import java.util.*

fun main(args: Array<String>) {
    var number: Long = 0
    val simpleObject = SimpleClass()
    number = simpleObject.getValue<Long>()
    println("Hi + $number")
}

class SimpleClass() {
    fun <T>getValue(): T {
        return 1000 as T
    }
}

但是如果我有以下内容,它将失败

But if I have the below, it fails

import java.util.*

fun main(args: Array<String>) {
    var number: Long? = null
    val simpleObject = SimpleClass()
    number = simpleObject.getValue<Long>()
    println("Hi + $number")
}

class SimpleClass() {
    fun <T>getValue(): T {
        return 1000 as T
    }
}

报告的错误在number = simpleObject.getValue<Long>()

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long

为什么初始化var number: Long ? = nullvar number: Long = 0会有不同的结果?我有什么不对吗?

Why when I initialise var number: Long ? = null and var number: Long = 0 have different result? Did I get anything wrong?

已更新

使用下面的解决方法,结果还可以.但是使用了一个额外的临时变量.

A workaround using the below, the result is okay. But an additional temp variable is used.

import java.util.*

fun main(args: Array<String>) {
    var number: Long? = null
    val simpleObject = SimpleClass()
    val temp = simpleObject.getValue<Long>()
    number = temp
    println("Hi + $number")
}

class SimpleClass() {
    fun <T>getValue(): T {
        return 1000 as T
    }
}

推荐答案

让我们看一下生成的字节码:

Let's take a look into generated bytecode:

fun <T> getValue(): T {
    return 1000 as T
}

// becomes

public final getValue()Ljava/lang/Object;
   L0
    LINENUMBER 17 L0
    SIPUSH 1000
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    CHECKCAST java/lang/Object
    ARETURN
   L1
    LOCALVARIABLE this LSimpleClass; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

如您所见,此方法不会强制转换 1000Long,它只是确保该对象的类型为java/lang/Object(嗯,是),并返回1000作为Integer对象.

As you can see, this method does not cast 1000 to a Long it simply ensures, that the object is of type java/lang/Object (well, it is) and returns the 1000 as an Integer object.

因此,您可以使用任何类型调用(注意:仅调用)此方法,并且不会引发异常.但是,将结果存储在变量中会调用实际的类型转换,这可能会导致ClassCastException

Therefore, you may call (note: call only) this method with any type and this will not throw exception. However, storing the result in a variable invokes real cast which may lead to ClassCastException

fun f3() {
    val simpleObject = SimpleClass()
    // L0
    //   LINENUMBER 16 L0
    //   NEW SimpleClass
    //   DUP
    //   INVOKESPECIAL SimpleClass.<init> ()V
    //   ASTORE 0

    simpleObject.getValue<SimpleClass>() // no problems
    // L1
    //   LINENUMBER 17 L1
    //   ALOAD 0
    //   INVOKEVIRTUAL SimpleClass.getValue ()Ljava/lang/Object;
    //   POP

    val number = simpleObject.getValue<SimpleClass>() // throws ClassCastException1
    // L2
    //   LINENUMBER 18 L2
    //   ALOAD 0
    //   INVOKEVIRTUAL SimpleClass.getValue ()Ljava/lang/Object;
    //   CHECKCAST SimpleClass
    //   ASTORE 1


    // L3
    //   LINENUMBER 19 L3
    //   RETURN
    // L4
    //   LOCALVARIABLE number LSimpleClass; L3 L4 1
    //   LOCALVARIABLE simpleObject LSimpleClass; L1 L4 0
    //   MAXSTACK = 2
    //   MAXLOCALS = 2
}

但是为什么将结果存储为Long?会引发异常?再次,让我们看一下字节码的区别:

But why storing the result as a Long? throws an exception? Again, let's take a look at the differences in bytecode:

var number: Long? = null              |    var number: Long = 0
                                      |
      ACONST_NULL                     |        LCONST_0
      CHECKCAST java/lang/Long        |        LSTORE 0
      ASTORE 0                        |

                number = simpleObject.getValue<Long>() [both]

      ALOAD 1                         |
              INVOKEVIRTUAL SimpleClass.getValue ()Ljava/lang/Object; [both]
      CHECKCAST java/lang/Long        |        CHECKCAST java/lang/Number
      ASTORE 0                        |        INVOKEVIRTUAL java/lang/Number.longValue ()J
                                      |        LSTORE 0

如您所见,number: Long的字节码将函数结果强制转换为Number,然后调用Number.longValue以便将值转换为Long(在Java中为long)

As you can see, the bytecode for number: Long casts the function result to a Number and then calls Number.longValue in order to convert the value to a Long (long in Java)

但是,number: Long?的字节码将函数结果直接转换为Long?(在Java中为Long),从而导致ClassCastException.

However, the bytecode for number: Long? casts the function result directly into the Long? (Long in Java) which leads to ClassCastException.

不确定,如果此行为记录在某处.但是,as运算符执行不安全的强制转换,编译器对此进行警告:

Not sure, if this behavior documented somewhere. However, the as operator performs unsafe cast and the compiler warns about it:

Warning:(21, 16) Kotlin: Unchecked cast: kotlin.Int to T

这篇关于无法在Kotlin中将java.lang.Integer强制转换为java.lang.Long(初始值为null时)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 19:48