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

JavaConverters

如何使用

引入依赖

import collection.JavaConverters._

集合显式调用 asJava ,asScala进行转化

在代码中经常会涉及scala和java集合的相互转换,担心其会产生性能上的问题,今天就来看看源码分析一下转换过程带来的代价。

先说结论:适配器模式(Adapter Pattern)实现,时间复杂度O(1),只会带来很小的性能开销。同时Java集合转为Scala后再转回Java会得到原来的对象,而非Wrapper套Wrapper

如何实现(源码分析)

以List转换为例
scala => java

测试代码:

object JavaConverterTest {
  def main(args: Array[String]): Unit = {
    import collection.JavaConverters._
    val list = List[String]("A", "B", "C")
    val jListWrapper = list.asJava
    println(jListWrapper)
  }
}

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

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

public final class JavaConverterTest$ {
    public static final JavaConverterTest$ MODULE$;

    public static {
        new JavaConverterTest$();
    }

    public void main(String[] args) {
        List list = List$.MODULE$.apply((Seq)Predef$.MODULE$.wrapRefArray((Object[])new String[]{"A", "B", "C"}));
        Predef$.MODULE$.println(JavaConverters$.MODULE$.seqAsJavaListConverter((Seq)list).asJava());
    }

    private JavaConverterTest$() {
        MODULE$ = this;
    }
}


根据反编译结果可以发现调用了JavaConverters的方法seqAsJavaListConverter

JavaConverters

object JavaConverters extends DecorateAsJava with DecorateAsScala

JavaConverters的方法全部继承于DecorateAsJava以及DecorateAsScala

DecorateAsJava

DecorateAsJava定义了一系列隐式转换方法

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

DecorateAsJava的方法seqAsJavaListConverter

  implicit def seqAsJavaListConverter[A](b : Seq[A]): AsJava[ju.List[A]] =
    new AsJava(seqAsJavaList(b))

便是提供了从:Seq[A] => AsJava[ju.List[A]]的隐式类型转换,从而提供了asJava的方法进行显示的转换

Decorators

AsJava对象是Decorators的内部类

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

op: => A: 这里不是传了个方法(有冒号),而是是名调用(call-by-name), 这个参数op实际上指代一个块(代码),且这个块的返回值为A,在这里也就是AsJava的泛型ju.List[A]

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

AsJavaConverters

def seqAsJavaList[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): 本身就是Java List包装成的Scala List => 去掉包装即可
  • 其他非null情况 => new SeqWrapper(s) (将scala List包装为Java 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接口的迭代器相关方法

迭代器相关包装实现:IterableWrapperTraitIteratorWrapper

注:java集合继承关系:

AbstractList 抽象类
List 接口
Collection 接口
Iterater 接口
AbstractCollection 抽象类
java => scala

详情见JListWrapper,略。

结论

由源码可以看出:对于列表类型的集合类型转换,时间复杂度为O(1),并不会对性能产生什么影响,只是做了个适配/包装(实现java接口的方法),并不存在集合数据的拷贝。

Map转换的一些点

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

  class MapWrapper[A, B](underlying: Map[A, B]) extends ju.AbstractMap[A, B] with Serializable { self =>
		//一些方法的实现
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值