我只是在学习Scala,并担心清理构造函数参数。
在Java中,我有一个这样的课程:
public class Example {
private A a;
private B b;
private SelectorA aSelector;
private SelectorB bSelector;
public Example(SelectorA aSelector, SelectorB bSelector) {
this.aSelector = Objects.requireNonNull(aSelector);
this.bSelector = Objects.requireNonNull(bSelector);
}
public void start() {
if (a == null) {
a = aSelector.select();
aSelector = null; // Removing reference.
}
if (b == null) {
b = bSelector.select();
bSelector = null; // Removing reference.
}
// Go on.
}
}
当然,它更复杂,有参数和东西。这个课程假设是一个长寿的课程,我只是想确保它没有任何它不需要的参考。
我即将把这个类移植到Scala并创建了这样的类:
class Example(_aSelector: Selector[A], _bSelector: Selector[B]) {
private lazy val _a = _aSelector() // Will _aSelector reference be cleared?
private lazy val _b = _bSelector() // Will _bSelector reference be cleared?
def start() = {
// Use _a.
// Use _b.
// Go on.
}
}
同样,它会更复杂,但这个想法很清楚。所以,问题是:
Scala是否能够检测不再需要哪些构造函数参数(上例中的_aSelector
和_bSelector
)?或者我是否必须明确清除参考文献?
_a
_aSelector = null
_b
_bSelector = null
P.S。我理解GC是检测范围外引用的那个,但Scala编译器是定义变量范围的一个,因此它是一个定义行为。
答案 0 :(得分:6)
使用lazy val
,您明确请求_a
仅在第一次访问时初始化。这需要在构造函数结束后保留对_aSelector
的引用,至少在第一次访问_a
之前。
然而 - 这让我感到惊讶 - 看来scalac非常聪明,可以在_aSelector
成功初始化后生成_a
的代码。
您可以使用scalac -Xprint:mixin
验证这一点:
<强> Test.scala:强>
class Test(factory: () => Int) {
lazy val x = factory()
}
然后:
$ scalac -Xprint:mixin Test.scala
class Test extends Object {
@volatile private[this] var bitmap$0: Boolean = false;
private def x$lzycompute(): Int = {
{
Test.this.synchronized({
if (Test.this.bitmap$0.unary_!())
{
Test.this.x = Test.this.factory.apply$mcI$sp();
Test.this.bitmap$0 = true;
()
};
scala.runtime.BoxedUnit.UNIT
});
Test.this.factory = null // <-- LOOK HERE
};
Test.this.x
};
<paramaccessor> private[this] val factory: Function0 = _;
lazy private[this] var x: Int = _;
<stable> <accessor> lazy def x(): Int = if (Test.this.bitmap$0.unary_!())
Test.this.x$lzycompute()
else
Test.this.x;
def <init>(factory: Function0): Test = {
Test.this.factory = factory;
Test.super.<init>();
()
}
};
因此,第一次访问_a
并成功初始化后,是,将释放对_aSelector
的引用,GC将能够收回它。
答案 1 :(得分:0)
你不能在这里使用WeakReferences来允许GC在弱引用时清除引用,然后只需更改你的防护以确定它们是否仍然可用?如果他们不是注入选择器,那么可以注入一个知道如何创建新引用的工厂。一种老化的缓存方法......