Происходят две вещи.
Во-первых, когда xs
имеет тип * 10039 * stati Range
, тогда этот вызов sum
является вызовом метода * monmorphi c (поскольку sum
является окончательным в Range
), и JVM может легко встроить этот метод и оптимизировать его. Когда xs
имеет тип stati c типа Seq
, он становится вызовом метода megamorphi c, который не будет встроенным и полностью оптимизированным.
Вторым является то, что вызываемые методы являются на самом деле не то же самое . Компилятор генерирует два sum
метода в Range
:
scala> :javap -p scala.collection.immutable.Range
Compiled from "Range.scala"
public abstract class scala.collection.immutable.Range extends scala.collection.immutable.AbstractSeq<java.lang.Object> implements scala.collection.immutable.IndexedSeq<java.lang.Object>, scala.collection.immutable.StrictOptimizedSeqOps<java.lang.Object, scala.collection.immutable.IndexedSeq, scala.collection.immutable.IndexedSeq<java.lang.Object>>, java.io.Serializable {
...
public final <B> int sum(scala.math.Numeric<B>);
...
public final java.lang.Object sum(scala.math.Numeric);
...
}
Первый содержит фактическую реализацию, которую вы видите в исходном коде. И, как вы можете видеть, он возвращает без коробки int
. Второй:
public final java.lang.Object sum(scala.math.Numeric);
Code:
0: aload_0
1: aload_1
2: invokevirtual #898 // Method sum:(Lscala/math/Numeric;)I
5: invokestatic #893 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
8: areturn
Как вы видите, он просто вызывает другой метод sum
и помещает int
в java.lang.Integer
.
Так в вашем методе seq
компилятор знает только о существовании метода sum
, который имеет тип возврата java.lang.Object
, и вызывает его. Вероятно, он не становится встроенным, и возвращаемое java.lang.Integer
необходимо снова распаковать, чтобы seq
могло вернуть int
. В range
компилятор может генерировать вызов «реального» метода sum
без необходимости ставить и распаковывать результаты. JVM также может выполнять работу по внедрению и оптимизации кода.