映射:为类型整数和双精度但不是字符串定义方法 [英] Map: Defining a Method for Type Integer and Double but not String

查看:120
本文介绍了映射:为类型整数和双精度但不是字符串定义方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图为我的新的 Map 类定义一个方法 putIfGreaterThan()只有当新值大于旧值时,才会使用新值替换旧值)。



据我所知,我可以通过合成(通过具有私人最终地图< String,Double>地图; 在新类中,然后将 Map 传递给构造函数),或者通过在我的新类中实现 Map 接口并传递一个 Map 给构造函数(尽管我不确定哪种方法更好)。

我的主要问题是我需要能够在< String,Double> 和<$ c上调用方法 putIfGreaterThan() $ c>< String,Integer> ,但不在< String,String> 上(因为调用它没有意义< String,String> )。如果我使用泛型(< K,V> ),客户端可以传递一个< String,String> 不允许。另一方面,如果我允许 Double ,我将无法传递整数,反之亦然。我怎样才能定义一个方法来允许Integer或Double而不是String?

注意:我无法定义两个构造函数(一个用于Double,一个用于Integer)因为我得到了错误:方法XX的擦除与XX类型中的另一个方法相同。

解决方案

您可以使用装饰器并将泛型限制为 Number 的子类型,您可以使用这个答案。它接受数字实例的字符串表示并创建一个 BigDecimal 的实例 - 从而规避任何类型的转换。



下面你会发现装饰器的相关实现细节,当然你需要重写 Map 接口的其余方法。

  public class GreaterThanDecorator< K,V extends Number>实现Map< K,V> {

私人最终地图< K,V>代表;

public GreaterThanDecorator(Map< K,V> delegate){
this.delegate = delegate;
}

public V putIfGreaterThan(K key,V value){
V old = delegate.get(key);
if(old == null){
delegate.put(key,value);
返回null;
}

BigDecimal newValue = new BigDecimal(value.toString());
BigDecimal oldValue = new BigDecimal(old.toString());

if(newValue.compareTo(oldValue)> = 1)
old = delegate.put(key,value);

返回旧的;





请随时禁止其他子类型的 Number ,即通过抛出一个异常,正如您认为的那样。


I'm attempting to define a method putIfGreaterThan() for my new Map class (given a key it replaces the old value with the new value only if the new value is greater than the old value).

I understand I could accomplish this either via composition (by having a private final Map<String, Double> map; in new class and then passing a Map to constructor) or by implementing the Map interface in my new class and passing a Map to the constructor (although I'm not sure which approach is superior).

My main problem is that I need to be able to call the method putIfGreaterThan() on <String, Double> and <String, Integer> but not on <String, String> (bec it doesn't make sense to call it on <String, String> ). If I use generics ( <K, V>) the client can pass a <String, String> which is not allowed. On the other hand if I allow a Double I will not be able to pass an Integer or vice versa. How can I define a method to allow either Integer or Double but not String?

Note: I'm unable to define two constructors (one for Double and one for Integer) bec I get the error: Erasure of method XX is the same as another method in type XX .

解决方案

You can use the decorator pattern and limit the generics to subtypes of Number, which you can than compare without casting with a little trick taken from this answer. It takes the string representation of the number instances and creates an instance of BigDecimal - thus circumventing casting of any kind.

Below you find the relevant implementation details of the decorator, of course you'll need to override the remaining methods of the Map interface.

public class GreaterThanDecorator<K, V extends  Number> implements Map<K, V> {

    private final Map<K, V> delegate;

    public GreaterThanDecorator(Map<K, V> delegate) {
        this.delegate = delegate;
    }

    public V putIfGreaterThan(K key, V value) {
        V old = delegate.get(key);
        if (old == null) {
            delegate.put(key, value);
            return null;
        }

        BigDecimal newValue = new BigDecimal(value.toString());
        BigDecimal oldValue = new BigDecimal(old.toString());

        if (newValue.compareTo(oldValue) >= 1)
            old = delegate.put(key, value);

        return old;
    }

} 

Feel free to forbid the other subtypes of Number, i.e. by throwing an exception, as you see fit.

这篇关于映射:为类型整数和双精度但不是字符串定义方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆