我想知道Scala如何管理这些对象的过度分配和释放。如何查找现有的子列表,例如将1
连接到List(1,2,3)
。如何跟踪某个List
未被使用,并允许垃圾收集器释放它?
我会像这样设计它
class List {
private Map<Integer,WeakRef<List>> listCache;
public List(Integer head,List tail) {...}
public synchronized List prepend(Integer i) {
if (listCache.get(i) != null) {
if (listCache.get(i).get() == null) {
listCache.put(i,new List(i,this));
}
}
}
Scala如何设计?它是否能很好地处理过多的分配和解除分配?它对线程有什么作用?
答案 0 :(得分:3)
让我们写一个简单的List
类:
sealed abstract class MyList[+T] {
def head: T
def tail: MyList[T]
def isEmpty: Boolean
def prepend[T1 >: T](el: T1): MyList[T1]
}
object EmptyList extends MyList[Nothing] {
def head: Nothing = throw new java.util.NoSuchElementException("head of an empty list")
def tail: MyList[Nothing] = throw new UnsupportedOperationException("unsupported operation exception")
def isEmpty = true
def prepend[T1 >: Nothing](el: T1): MyList[T1] = new Cons(el, this)
override def toString = "EmptyList"
}
final class Cons[+T](val head: T, val tail: MyList[T]) extends MyList[T] {
def isEmpty = false
def prepend[T1 >: T](el: T1): MyList[T1] = new Cons(el, this)
override def toString = head + ", " + tail.toString
}
Scala中的列表就是这样的。那么,考虑一下你提到的例子:
scala> val list = new Cons(1, new Cons(2, new Cons(3, EmptyList)))
list: Cons[Int] = 1, 2, 3, EmptyList
scala> val newList = list.prepend(1)
newList: MyList[Int] = 1, 1, 2, 3, EmptyList
所以,问题:
prepend
被调用的列表。当然,如果我创建另一个这样的列表:
val list2 = list.prepend(1)
然后newList
和list2
将共享list
,但即使它们包含相同的元素,也会是不同的列表。
你可能会质疑(正如在评论中所做的那样)这种可重用性模式是否切实可行,或者它是否会带来现实生活中的任何收益,而答案就是 lot 算法利用它。
事实上,让我指出this question,其中所谓的“慢”代码实际上比所谓的“快速”代码以及答案中建议的替代代码更快。 原因为什么“慢”代码无关紧要就是这种重用模式。
答案 1 :(得分:1)
Scala根本不管理这些对象的重新分配。它们作为普通的JVM对象在堆上创建,并且由JVM收集的垃圾就像任何其他Java或Scala对象一样。正如您对问题的评论所指出的那样,它不会重复使用从之前调用List()创建的列表 - 它始终是一个新对象。
通过连接列表澄清情况 - 在这种情况下,生成的List对象 保持对列表两端的引用,但它仍然没有执行任何特殊的缓存使用过的清单或类似的东西。