Java 检索;“标准值”;从一个集合<;T>;其中T有一个自定义的等于()

Java 检索;“标准值”;从一个集合<;T>;其中T有一个自定义的等于(),java,set,Java,Set,我有一个类Foo,它正确地覆盖了equals()和hashCode() 我还想使用HashSet来跟踪“规范值”,例如,我有一个类,我想这样写,这样如果我有两个独立的对象是等价的,我可以将它们合并为对同一对象的引用: class Canonicalizer<T> { final private Set<T> values = new HashSet<T>(); public T findCanonicalValue(T value)

我有一个
类Foo
,它正确地覆盖了
equals()
hashCode()

我还想使用
HashSet
来跟踪“规范值”,例如,我有一个类,我想这样写,这样如果我有两个独立的对象是等价的,我可以将它们合并为对同一对象的引用:

class Canonicalizer<T>
{
    final private Set<T> values = new HashSet<T>(); 

    public T findCanonicalValue(T value)
    {
        T canonical = this.values.get(value);
        if (canonical == null)
        {
           // not in the set, so put it there for the future
           this.values.add(value);
           return value;
        }
        else
        {
           return canonical;
        }
    }
}

我会使用如下的哈希映射:

final private Map<T, T> values = new HashMap<T, T>(); 
public T findCanonicalValue(T value)
{
    T canon = this.values.get(value);
    if (canon == null)
    {
       // not in the set, so put it there for the future
       this.values.put(value, value);
       return value;
    }
    else
    {
       // in the set
       return canon;
    }
}
final private Map value=new HashMap();
公共T findCanonicalValue(T值)
{
T canon=this.values.get(value);
如果(佳能==null)
{
//不在片场,所以把它放在未来
this.values.put(value,value);
返回值;
}
其他的
{
//现场
返回佳能;
}
}

它仍然有点笨拙,但它应该比映射和列表(少一个数据结构)稍微有效一些。

映射似乎是正确的想法,但是为什么不从某个对象T映射到相应的规范对象呢

class Canonicalizer<T>
{
    final private Map<T, T> values = new HashMap<T, T>(); 

    public T findCanonicalValue(T value)
    {
        T canonical = this.values.get(value);
        if (canonical == null)
        {
            // not in the map, so put it there for the future
            this.values.put(value, value);
            return value;
        }
        else
        {
            return canonical;
        }
    }
}
类规范化器
{
最终私有映射值=新HashMap();
公共T findCanonicalValue(T值)
{
T canonical=this.values.get(value);
if(规范==null)
{
//不在地图上,所以把它放在未来
this.values.put(value,value);
返回值;
}
其他的
{
返回规范;
}
}
}

使用番石榴的
实习生


这正是它的用途。

使用ConcurrentMap,它更简单一些。(和线程安全)

私有最终ConcurrentMap值=新ConcurrentHashMap();
公共T findCanonicalValue(T值){
值。putIfAbsent(值,值);
返回值。获取(值);
}

在许多情况下,您希望这种容器用于需要由不同线程访问的对象缓存;如果是这样,请确保不要忽略并发性问题,并注意线程安全映射实现通常不支持空键。如果出于某种原因您不能使用番石榴,请至少看一下源代码:

公共期末班实习生{
私有内部用户(){}
/**
*返回一个新的线程安全interner,该interner保留对
*它所拘留的每个实例,从而防止这些实例被
*垃圾已收集。如果此保留是可接受的,则此实现可能
*性能优于{@link#newWeakInterner}。
*/
公共静态Interner newStrongInterner(){
最终ConcurrentMap=new MapMaker().makeMap();
返回新的Interner(){
公共电子实习生(电子样本){
E canonical=map.putIfAbsent(checkNotNull(sample),sample);
return(canonical==null)?示例:canonical;
}
};
}

HashSet实际上在内部使用了一个HashMap,它将每个键的值设置为一个虚拟对象,因此如果需要使用get,最好使用map。
class Canonicalizer<T>
{
    final private Map<T, T> values = new HashMap<T, T>(); 

    public T findCanonicalValue(T value)
    {
        T canonical = this.values.get(value);
        if (canonical == null)
        {
            // not in the map, so put it there for the future
            this.values.put(value, value);
            return value;
        }
        else
        {
            return canonical;
        }
    }
}
private final ConcurrentMap<T, T> values = new ConcurrentHashMap<T, T>();  
public T findCanonicalValue(T value) { 
    values.putIfAbsent(value, value);
    return values.get(value);
}
public final class Interners {
  private Interners() {}

  /**
   * Returns a new thread-safe interner which retains a strong reference to
   * each instance it has interned, thus preventing these instances from being
   * garbage-collected. If this retention is acceptable, this implementation may
   * perform better than {@link #newWeakInterner}.
   */
  public static <E> Interner<E> newStrongInterner() {
    final ConcurrentMap<E, E> map = new MapMaker().makeMap();
    return new Interner<E>() {
      public E intern(E sample) {
        E canonical = map.putIfAbsent(checkNotNull(sample), sample);
        return (canonical == null) ? sample : canonical;
      }
    };
  }