有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java映射:为Integer和Double类型定义一个方法,而不是String

我正在尝试为我的新Map类定义一个方法putIfGreaterThan()给定一个键,只有当新值大于旧值时,它才会用新值替换旧值)

我知道我可以通过组合(在新类中有一个private final Map<String, Double> map;,然后将一个Map传递给构造函数)或者在我的新类中实现Map接口,然后将一个Map传递给构造函数来实现这一点(尽管我不确定哪种方法更好)

我的主要问题是,我需要能够在<String, Double><String, Integer>上调用方法putIfGreaterThan(),但不能在<String, String>上调用(因为在<String, String>上调用它没有意义)。如果我使用泛型(<K, V>),客户端可以传递一个不允许的<String, String>。另一方面,如果我允许Double,我将无法通过Integer,反之亦然。如何定义一个允许整数或双精度但不允许字符串的方法

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


共 (3) 个答案

  1. # 1 楼答案

    您可以使用decorator模式并将泛型限制为Number的子类型,您可以使用this answer中的一个小技巧在不强制转换的情况下进行比较。它采用数字实例的字符串表示,并创建一个BigDecimal实例,从而避免任何类型的强制转换

    下面是decorator的相关实现细节,当然您需要覆盖Map接口的其余方法

    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;
        }
    
    } 
    

    您可以随意禁止Number的其他子类型,也就是抛出一个异常,这是您认为合适的

  2. # 2 楼答案

    不幸的是,泛型和数字不能很好地结合在一起。但你可以这样做:

    public class MyMap {
        private final Map<String, Number> map = new HashMap<>();
    
        public void putInt(String key, int value) {
            map.put(key, value);
        }
    
        public void putDouble(String key, int value) {
            map.put(key, value);
        }
    
        public void putIfGreaterThan(String key, Number value) {
            if (value instanceof Double) {
                double doubleValue = (Double) value;
                map.compute(key, (k, v) -> {
                    if (!(v instanceof Double) || v.doubleValue() > doubleValue) {
                        return v;
                    } else {
                        return value
                    }
                });
            } else if (value instanceof Integer) {
                int intValue = (Integer) value;
                map.compute(key, (k, v) -> {
                    if (!(v instanceof Integer) || v.intValue() > intValue) {
                        return v;
                    } else {
                        return value
                    }
                });
            } else {
                throw new IllegalArgumentException("Expected Double or Integer, but got " + value);
            }
        }
    
    }
    
  3. # 3 楼答案

    理想情况下,您应该声明一个引入类型参数的方法,该类型参数为extends V & Comparable<? super V>,但这不是有效的Java

    但是,您可以定义静态方法而不使用&

    public static <K, V extends Comparable<? super V>> void putIfGreater(
        Map<K,V> map, K key, V value
    ) {
        V old = map.get(key);
        if (old != null && value.compareTo(old) > 0) {
            map.put(key, value);
        }
    
        // Or: 
        //map.computeIfPresent(key, (k, old) -> value.compareTo(old) > 0 ? value : old);
    }
    

    如果使用不同的构造,那么对于VComparable<? super V>的情况,类型需要不同。如果两个构造函数具有相同的擦除,那么可能是时候有意义地命名静态创建方法了