位置:首页 > Scala > Scala与Java集合类型转换性能分析与源码解读

Scala与Java集合类型转换性能分析与源码解读

时间:2026-08-21  |  作者:风起客  |  阅读:0

Ja vaConverters

如何使用

先引入依赖。

[Scala源码] Scala与Ja va间集合类型转换的性能分析

import collection.Ja vaConverters._

集合可以显式调用 asJa vaasScala 进行转化。

在代码中,经常会涉及scala和ja va集合的相互转换。很多人会担心这里是否会产生性能问题。下面结合源码,分析一下转换过程带来的代价。

先给出结论:通过适配器模式(Adapter Pattern)实现,时间复杂度为O(1),仅会产生极小的性能开销。

而且,将Ja va集合转换为Scala后再转换回Ja va,得到的是原始对象,并非是Wrapper套Wrapper的形式。

如何实现(源码分析)

以List转换为例

scala => ja va

测试代码:

object Ja vaConverterTest {
  def main(args: Array[String]): Unit = {
    import collection.Ja vaConverters._
    val list = List[String]("A", "B", "C")
    val jListWrapper = list.asJa va
    println(jListWrapper)
  }
}

借助CFR反编译得到:在线反编译工具网址

/*
 * Decompiled with CFR 0.150.
 * 
 * Could not load the following classes:
 *  scala.Predef$
 *  scala.collection.Ja vaConverters$
 *  scala.collection.Seq
 *  scala.collection.immutable.List
 *  scala.collection.immutable.List$
 */
import scala.Predef$;
import scala.collection.Ja vaConverters$;
import scala.collection.Seq;
import scala.collection.immutable.List;
import scala.collection.immutable.List$;

public final class Ja vaConverterTest$ {
    public static final Ja vaConverterTest$ MODULE$;

    public static {
        new Ja vaConverterTest$();
    }

    public void main(String[] args) {
        List list = List$.MODULE$.apply((Seq)Predef$.MODULE$.wrapRefArray((Object[])new String[]{"A", "B", "C"}));
        Predef$.MODULE$.println(Ja vaConverters$.MODULE$.seqAsJa vaListConverter((Seq)list).asJa va());
    }

    private Ja vaConverterTest$() {
        MODULE$ = this;
    }
}


根据反编译结果可以发现,调用了Ja vaConverters的方法seqAsJa vaListConverter

Ja vaConverters

object Ja vaConverters extends DecorateAsJa va with DecorateAsScala

Ja vaConverters的方法全部继承于DecorateAsJa va以及DecorateAsScala

DecorateAsJa va

DecorateAsJa va定义了一系列隐式转换方法。

关于隐式转换方法,个人的理解就是:提供了一系列类型间的转换供编译器选择。当编译不成功时,编译器会去找合适的隐式方法,将类型进行适当转换,从而使得编译通过。

DecorateAsJa va的方法seqAsJa vaListConverter

  implicit def seqAsJa vaListConverter[A](b : Seq[A]): AsJa va[ju.List[A]] =
    new AsJa va(seqAsJa vaList(b))

这便是提供了从:Seq[A] => AsJa va[ju.List[A]] 的隐式类型转换。

因此,集合就获得了asJa va的方法,用于显示的转换。

Decorators

AsJa va对象是Decorators的内部类。

private[collection] object Decorators {
	class AsJa va[A](op: => A) {
 	 /** Converts a Scala collection to the corresponding Ja va collection */
	  def asJa va: A = op
	}
	//其他内部类
}

op: => A:此处并非传递一个方法,而是名调用(call-by-name)。

这个参数op实际上代表一个代码块。该代码块的返回值为A,在这里也就是AsJa va的泛型ju.List[A]

这里可以看出,具体将scala集合List转化为util.List的逻辑,在seqAsJa vaList方法里。

AsJa vaConverters

def seqAsJa vaList[A](s: Seq[A]): ju.List[A] = s match {
  case null                   => null
  case JListWrapper(wrapped)  => wrapped.asInstanceOf[ju.List[A]]
  case _                      => new SeqWrapper(s)
}

这里按Seq类型进行了分类:

  • JListWrapper(wrapped):本身就是Ja va List包装成的Scala List,直接去掉包装即可。
  • 其他非null情况:new SeqWrapper(s),即将scala List包装为Ja va List。

Wrapper

点进SeqWrapper,看看具体怎么包装的。

private[collection] trait Wrappers {
 
  trait IterableWrapperTrait[A] extends ju.AbstractCollection[A] {
    val underlying: Iterable[A]
    def size = underlying.size
    override def iterator = IteratorWrapper(underlying.iterator)
    override def isEmpty = underlying.isEmpty
  }

  case class IteratorWrapper[A](underlying: Iterator[A]) extends ju.Iterator[A] with ju.Enumeration[A] {
    def hasNext = underlying.hasNext
    def next() = underlying.next()
    def hasMoreElements = underlying.hasNext
    def nextElement() = underlying.next()
    override def remove() = throw new UnsupportedOperationException
  }
    
  case class SeqWrapper[A](underlying: Seq[A]) extends ju.AbstractList[A] with IterableWrapperTrait[A] {
    def get(i: Int) = underlying(i)
  }
}

SeqWrapperWrapper下的一个内部样例类。

它继承了AbstractList,实现了其抽象方法get,以及Iterable接口的迭代器相关方法。

迭代器相关包装实现包括:

  • IterableWrapperTrait
  • IteratorWrapper

注:ja va集合继承关系:

graph BT
	A(AbstractList 抽象类) ---> B(List 接口) ---> D(Collection 接口) ---> E(Iterater 接口)
	A ---> C(AbstractCollection 抽象类) ---> D

ja va => scala

详情见JListWrapper,略。

结论

由源码可以看出:对于列表类型的集合类型转换,时间复杂度为O(1)

并不会对性能产生什么影响,只是做了个适配/包装(实现ja va接口的方法),并不存在集合数据的拷贝。

Map转换的一些点

selfthis的引用。

MapWrapperWrapper内部类的时候,定义的self引用可以将内部类的this和外部类的this进行区分。

  class MapWrapper[A, B](underlying: Map[A, B]) extends ju.AbstractMap[A, B] with Serializable { self =>
		//一些方法的实现
  }

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多