【问题标题】:Why is there no StrongReference object?为什么没有 StrongReference 对象?
【发布时间】:2013-03-27 04:26:05
【问题描述】:

我正在实现一些行为,这些行为有时可以从使用弱引用中受益。我希望班级的用户能够在施工时指出是否是这种情况。由于WeakReference 扩展Reference 乍一看似乎我可以做类似的事情(这是一个模型,而不是我真正想要做的事情):

public class Container<T> {
    private boolean useWeakRef;
    private Reference<T> ref;

    public Container(boolean isWeak) {
        useWeakRef = isWeak;
    }

    public void store(T val) {
        if(useWeakRef) {
            ref = new WeakReference<>(val);
        } else {
            ref = new StrongReference<>(val);
        }
    }

    // May return null
    public T get() {
        return ref.get();
    }
}

但是没有StrongReference类,根据Reference javadocs

因为引用对象是与垃圾收集器密切配合实现的,所以这个类不能直接子类化。

所以我不能创建自己的 Reference 子类来保存对对象的强(即正常)引用。这似乎意味着不可能创建一个隐藏它是否使用来自调用者的弱(或软)引用的类。

我真的不明白为什么这个类不存在,StrongReference 对象应该总是从 get() 返回对象,除非已调用 clear()。为什么这个不见了? StrongReference 在某种程度上与 Reference 不一致吗?这将使构建通用引用持有者对象变得更加简单。

【问题讨论】:

  • 如果你真的需要它,实现该功能的接口也很简单。
  • 是的,我知道有一些变通方法,但我认为 Java 设计人员有意避免包含这个看似合乎逻辑的类,我想知道他们为什么这样做。
  • +1。还有 AtomicReference,它是一个强大且线程安全的引用,但它没有实现相同的接口。
  • 我冒昧地认为你假设太多了 :-) 也许在 Oracle 将 Java 出售给关心的人之后的未来版本中。无论如何 +1 开发者的焦虑。
  • 在我看来,“为什么设计师要采用 X 实现”的问题是完全有建设性的。例如,为什么 Guava 的weakKey MapMaker 对象使用== 而不是.equals()?答案是因为将.equals() 与弱引用结合使用会有些不一致且容易出错,但他们的文档对此效果并不十分清楚。

标签: java memory-management reference


【解决方案1】:

当我需要这样做时,我只是创建了一个自定义 Reference 接口和一个 WeakReference 的简单子类。这很烦人,但已经尽你所能了。

public interface MyReference<T> {
  public T get();
}

public class MyWeakReference<T> extends WeakReference<T> implements MyReference<T> {
}

public class MyStrongReference<T> implements MyReference<T> {
  // obvious implementation here ...
}

更新:

澄清一下,我不知道为什么这首先没有包含在 jdk 中(我也希望它已经包含),但是,我觉得这是一个合理的解决方法.

对于那些寻求证明这个想法的人,我发现在实现自定义缓存时有必要,其中引用的强度是缓存配置的一部分。

【讨论】:

  • 这不能回答问题。问题是问为什么 Java 开发人员没有实现这个。
  • @StephenC - 是的,这是问题的一部分。但是,说“这似乎意味着不可能创建一个隐藏它是否使用来自调用者的弱(或软)引用的类”的部分似乎也暗示了对问题的“解决方案”的渴望。
【解决方案2】:

你不能继承 Reference 因为它没有任何公共/受保护的构造函数。但是有一个解决方法:

class StrongReference<T> extends WeakReference<T> {
    private final T referent;

    StrongReference(T referent) {
        super(null);
        this.referent = referent;
    }

    @Override
    public T get() {
        return referent;
    }

    // implement other methods
}

【讨论】:

  • 这对我来说看起来很骇人听闻。继承描述了一种“是”关系,您将很难争辩 StrongReference “是”WeakReference :)
  • 同意。我使用的实现(在我切换到 Guava 之前)是一个包装器 StrongOrWeakReference&lt;T&gt;,它直接包含 WeakReference&lt;T&gt;T,具体取决于对象的构造方式,并实现了 get()clear()
  • @creinig:我很确定强引用实际上是弱引用的超集。它不仅可以让你找到对象,就像弱引用一样,它还可以让它保持活动状态/防止对其进行垃圾回收。
  • @BenVoigt:但是 WeakReference 的全部意义在于它允许 GC 收集引用的实例。从 WeakReference 继承 StrongReference 意味着您可以将 StrongReference 传递给任何期望 WeakReference 的客户端,即您可以传递与预期行为完全相反的东西。这没有什么特别的意义:)
  • @creinig:期望弱引用的客户端可以传递强引用,就像期望 32 位整数的客户端可以传递 8 位整数一样,或者期望 int? 的客户端可以被通过int.
【解决方案3】:

Guava 的 LocalCache 使用 StrongValueReference 类,它复制了我想要 StrongReference 类做的事情。虽然很遗憾 Guava 没有将其公开为公共类,但我认为这是确认这是 JDK 中缺少的功能,并且可以在必要时复制它。

也就是说,大多数需要抽象他们正在使用的引用类型的用例可能能够像我一样直接使用Guava's Cache 行为。我鼓励任何遇到这个问题的人在自己重新发明这种抽象引用行为之前探索 Guava 现有的缓存机制。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-06
    • 2013-04-24
    • 2020-11-30
    • 2015-04-11
    相关资源
    最近更新 更多