在我的專案中,我正在使用各種處理程式對不同原始型別的陣列執行邏輯,但我遇到了這個運行時錯誤:
[error] java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [B ([Ljava.lang.Object; and [B are in module java.base of loader 'bootstrap')
在這種情況下,我正在使用Bytes,因此[B, 但我的一個函式回傳了[Ljava.lang.Object(在運行時!)。如何確保我的泛型函式回傳原始陣列而不是物件陣列?
這是重現它的最小示例:
package asdf
import scala.reflect.ClassTag
import java.nio.charset.StandardCharsets
object Main {
trait Helper[A, B] {
def decode(bytes: Array[Byte]): Array[A]
def aggregate(values: Array[A]): B
}
object StringHelper extends Helper[Byte, String] {
def decode(bytes: Array[Byte]): Array[Byte] = bytes.filter(_ != 0)
def aggregate(values: Array[Byte]): String = new String(values, StandardCharsets.UTF_8)
}
object IntHelper extends Helper[Int, Int] {
def decode(bytes: Array[Byte]): Array[Int] = bytes.map(_.toInt)
def aggregate(values: Array[Int]): Int = values.sum
}
def decodeAgg[A, B](bytes: Array[Byte], helper: Helper[A, B])(implicit ev: ClassTag[A]): B = {
val decoded = helper.decode(bytes)
val notFirstDecoded = decoded
.zipWithIndex
.filter({case (_, i) => i != 0})
.map(_._1)
.toArray
helper.aggregate(notFirstDecoded)
}
def main(args: Array[String]) {
val helper: Helper[_, _] = args(1) match {
case "int" => IntHelper
case "string" => StringHelper
case _ => throw new Exception("unknown data type")
}
val bytes = Array(97, 98, 99).map(_.toByte)
val aggregated = decodeAgg(bytes, helper)
println(s"aggregated to $aggregated")
}
}
運行sbt "run -- string"。
此示例的完整堆疊跟蹤:
[error] java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [B ([Ljava.lang.Object; and [B are in module java.base of loader 'bootstrap')
[error] at asdf.Main$StringHelper$.aggregate(Main.scala:12)
[error] at asdf.Main$.decodeAgg(Main.scala:29)
[error] at asdf.Main$.main(Main.scala:39)
我使用的是 Scala 2.12、JDK 13。我試過@specialized沒有效果。
uj5u.com熱心網友回復:
問題在于您toArray的通話:
val notFirstDecoded = decoded
.zipWithIndex
.filter({case (_, i) => i != 0})
.map(_._1)
.toArray
toArray采用隱式ClassTag引數 - 它需要知道陣列元素的運行時型別才能創建陣列。
當您向 提供隱式 ClassTag 引數時decodeAgg,很toArray高興接受您提供的內容。
def decodeAgg[A, B](bytes: Array[Byte], helper: Helper[A, B])(implicit ev: ClassTag[A]): B
可以看到 ClassTag 對應于 Helper 的第一個泛型引數。
您通過以下助手:
val helper: Helper[_, _] = args(1) match {
case "int" => IntHelper
case "string" => StringHelper
case _ => throw new Exception("unknown data type")
}
ClassTag 因此被推斷為 Object,這就是為什么你得到一個物件陣列。
請注意,如果您直接使用 IntHelper,則 ClassTag 會被限制為正確的型別,并且該函式會按預期作業。
val aggregated = decodeAgg(bytes, IntHelper)
解決思路
可能有多種方法來解決它。一種想法可能是通過 Helper 顯式提供 classTag
import scala.reflect.ClassTag
import java.nio.charset.StandardCharsets
object Main {
trait Helper[A, B] {
def decode(bytes: Array[Byte]): Array[A]
def aggregate(values: Array[A]): B
def classTag: ClassTag[A]
}
object StringHelper extends Helper[Byte, String] {
def decode(bytes: Array[Byte]): Array[Byte] = bytes.filter(_ != 0)
def aggregate(values: Array[Byte]): String = new String(values, StandardCharsets.UTF_8)
def classTag: ClassTag[Byte] = ClassTag(classOf[Byte])
}
object IntHelper extends Helper[Int, Int] {
def decode(bytes: Array[Byte]): Array[Int] = bytes.map(_.toInt)
def aggregate(values: Array[Int]): Int = values.sum
def classTag: ClassTag[Int] = ClassTag(classOf[Int])
}
def decodeAgg[A, B](bytes: Array[Byte], helper: Helper[A, B]): B = {
val decoded = helper.decode(bytes)
val notFirstDecoded = decoded
.zipWithIndex
.filter({case (_, i) => i != 0})
.map(_._1)
.toArray(helper.classTag)
helper.aggregate(notFirstDecoded)
}
def main(args: Array[String]) {
val helper = args(1) match {
case "int" => IntHelper
case "string" => StringHelper
case _ => throw new Exception("unknown data type")
}
val bytes = Array(97, 98, 99).map(_.toByte)
val aggregated = decodeAgg(bytes, helper)
println(s"aggregated to $aggregated")
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/403448.html
標籤:
上一篇:計算日期后自動更新資料庫欄位?
