寫java 和 scala 混合程式碼的時候遇到一個小問題
def extractRefInputFieldsWithType(exprs: JList[RexNode]): Array[(Int, RelDataType)] = {
val visitor = new InputRefVisitor
// extract referenced input fields from expressions
exprs.foreach(_.accept(visitor))
visitor.getFieldsWithType
}
final scala.Tuple2<Integer, RelDataType>[] refFields =
RexNodeExtractor.extractRefInputFieldsWithType(project.getProjects());
IDE提示的錯誤是返回的型別是 Tuple2<Object, RelDataType>
但是我們承接的型別是Tuple2<Integer, RelDataType>
這本質原因是因為scala中的Int和java的Integer並不對標。
從這個 api介紹中https://www.scala-lang.org/api/current/scala/Int.html我們可以知道scala中Int
是一個value class (繼承自 AnyVal
) 有點類似java中的新提案中的 value types,可以讓使用者定義的型別在執行時不需要裝箱拆箱操作,可以減少不必要的堆記憶體分配。
從Stack Overflow上看到這樣的測試樣例
class SomeClass {
def testIntTuple: (Int, Int) = (0, 1)
def testIntegerTuple: (java.lang.Integer, java.lang.Integer) = (0, 1)
def testIntArray: Array[Int] = Array(1, 2)
}
javap SomeClass
Compiled from "IntValue.scala"
public class org.apache.flink.table.planner.plan.stream.sql.SomeClass {
public scala.Tuple2<java.lang.Object, java.lang.Object> testIntTuple();
public scala.Tuple2<java.lang.Integer, java.lang.Integer> testIntegerTuple();
public int[] testIntArray();
public org.apache.flink.table.planner.plan.stream.sql.SomeClass();
}
通過反編譯之後的程式碼可以看到執行時表示的型別是Object型別,而如果直接返回的型別是Array[Int] 則相應的表示的型別是int[]
從上面這段描述可以看到,因為Int型別是value class 所以在執行時並不直接對應到java.lang.Integer
因為scala中實現了value class的語意,所以他不需要將其轉化成包裝類,這樣就可以獲得更好的效能,避免建立Int值時還需要堆上分配記憶體和建立參照。
因此轉到java class時/或者java的泛型引數時就沒有直接的Reference型別對映,而轉到陣列時,就可以直接表示為 primitive 陣列int[]
https://stackoverflow.com/questions/10248180/scala-tuple-type-inference-in-java
https://scala.cool/2017/07/scala-types-of-types-part-4/
https://docs.scala-lang.org/overviews/core/value-classes.html value class 介紹
https://www.jesperdj.com/2015/10/04/project-valhalla-value-types/ java value types
https://openjdk.org/projects/valhalla/ jep
本文來自部落格園,作者:Aitozi,轉載請註明原文連結:https://www.cnblogs.com/Aitozi/p/16686417.html