【问题标题】:Java Generics and Infinity (Comparable)Java 泛型和无穷大(可比较)
【发布时间】:2009-04-29 18:03:46
【问题描述】:

使用 Integer 类型,您可以这样做:

int lowest = Integer.MIN_VALUE;

如果我使用泛型怎么办?

K lowest = <...>;

我需要这个来实现类似于 PriorityQueue 的东西。 我可以访问要从队列中删除的节点,但这不是最低要求。

1. I need to make it the min by decreasing the key of that node,
2. And then remove the min.

我被困在第一步。我唯一能做的就是将节点的键设置为当前最小值。不知道够不够。

【问题讨论】:

  • 您能否提供一些示例代码来说明您希望如何使用 K?
  • 你能详细说明一下吗?一些相关的代码会很好。
  • 顺便提一下,数字文字的对象版本都扩展了 java.lang.Number。不幸的是,Number 没有 getMaximumValue() 之类的东西。
  • 问题是如何从PriorityQueue中移除一个已知对象?

标签: java generics comparable infinity


【解决方案1】:

对于所有 Comparable 类型,没有通用形式的 MIN_VALUEMAX_VALUE

考虑一个实现可比较的Time 类。没有MAX_VALUE 表示时间,即使它是可比的。

【讨论】:

    【解决方案2】:

    我试图想象什么样的场景需要这种行为。这是我能想到的最好的......

    警告:此代码很危险。请原谅我发布如此可憎的内容。这只是一个概念证明。

    public class Lowest<K> implements Comparable<K> {
        public int compareTo(K other) {
            return -1;
        }
    }
    

    然后……

    public class Test {
        public <K extends Comparable<K>> K findMaximum(List<K> values) throws Exception {
            K lowest = (K) new Lowest<K>(); /// XXX DANGER! Losing compile-time safety!!!
    
            K maximum = lowest;
            for (K value : values) {
                if (maximum.compareTo(value) < 0) {
                    maximum = value;
                }
            }
    
            if (maximum == lowest) {
                throw new Exception("Could not find a maximum value");
            } else {
                return maximum;
            }
        }
    }
    

    【讨论】:

    • 好吧,这太奇怪了。我们在一秒钟内对这个问题发表了相同的评论,然后我们等了 20 分钟,然后在 15 秒内发布了几乎相同的代码。我想我需要休息一下......
    • @mmyers:很奇怪!我想我会好好休息一下,我自己。 :)
    • 我不确定哪个更糟:我使用反射来查找构造函数(对于潜在的非平凡类),或者您将非 K 转换为 K。跨度>
    • 原来我的解决方案更糟糕(即使使用整数也很难)。 +1 这个并删除了我的。
    • 奇怪但基本上是个好主意!只要您没有通过新的最低值+1,这是一种保存方法。你应该让 Lowest 成为一个内部的“私有静态类”,也许有一个最终引用
    【解决方案3】:

    这没有任何意义......

    鉴于您当时不知道 K 是什么,(即您是在一般地实现它...呵呵!)您无法为其指定最小/最大界限。

    在 K 可能是 int、long、string OR 对象的情况下,您无法明智地猜测使用

    Integer.MIN_VALUE, "" OR NULL。

    我猜你正在寻找的是 K.MIN_VALUE_OF_EVENTUAL_TYPE,但它不存在。

    【讨论】:

    • 这可能是来自 C++ 背景的人,在这种情况下只使用 numeric_limits::max 和 numeric_limits::min 是微不足道的。这使您可以编写处理字符、双精度、整数、64 位整数甚至自定义数字类的代码。
    • 我在寻找相同的想法时偶然发现了这一点,这是我的用例: 1. 我有一个使用以下方法的接口Comparable&lt;?&gt; getGroupIndex(String groupName) 如果groupName 是,此方法返回null未知。 2.在我调用上述方法的类中,如果返回值为null,那么我想将其放在列表的末尾(将其视为是否返回了可比较类型的最大值)。我将通过返回一个最大值而不是 null 来解决这个问题,但只是想阐明一个用例。
    【解决方案4】:

    您可以创建一个包装类,为所有类型“添加”最小值和最大值。它只有两个静态实例,代表最小值和最大值,然后其他实例包装某种类型的其他值。当我们进行比较时,我们检查其中一项是最小值还是最大值,并返回正确的结果;否则我们只做与底层类型相同的比较。像这样的:

    class Extended<T extends Comparable<? super T>> implements Comparable<Extended<T>> {
        private Extended() { }
    
        private static Extended min = new Extended();
        private static Extended max = new Extended();
    
        @SuppressWarnings("unchecked")
        public static <T extends Comparable<? super T>> Extended<T> getMin() {
            return (Extended<T>)min;
        }
        @SuppressWarnings("unchecked")
        public static <T extends Comparable<? super T>> Extended<T> getMax() {
            return (Extended<T>)max;
        }
    
        public T value;
    
        public Extended(T x) { value = x; }
    
        public int compareTo(Extended<T> other) {
            if (this == other) return 0;
            else if (this == min || other == max) return -1;
            else if (this == max || other == min) return 1;
            else return this.value.compareTo(other.value);
        }
    }
    

    【讨论】:

      【解决方案5】:

      考虑不要让K 成为泛型,而是使用包装原始包装器的接口(双重包装器!)。

      import java.util.HashMap;
      
      
      public class NodeWrapper<K extends Comparable<K>> implements Comparable<NodeWrapper<K>> {
      
          private static HashMap<Class, NodeWrapper> minVals = new HashMap<Class, NodeWrapper>();
      
          private K value;
      
          private NodeWrapper() {
              super();
          }
      
          public NodeWrapper(K value, Class<K> clazz) {
              super();
              this.value = value;
      
              if (minVals.get(clazz)==null) {
                  minVals.put(clazz, new NodeWrapper<K>());
              }
          }
      
          public K getValue() {
              return value;
          }
      
          public static NodeWrapper getMinValue(Class clazz){
              return minVals.get(clazz);
          }
      
          public void setValue(K value) {
              this.value = value;
          }
      
          @Override
          public int compareTo(NodeWrapper<K> o) {
              NodeWrapper min = minVals.get(this.getClass());
              if (this==min && o==min)  {
                  return 0;
              } else if (this==min){
                  return -1;
              } else if (o==min){
                  return 1;
              } else {
                  return this.value.compareTo(o.value);
              }
          }
      
      }
      

      简而言之,这个想法是,每当实例化一个新类时,都会创建一个最小值并将其放入存储每个类的最小值的静态哈希图中。 (事实上​​,这些值根本不是什么,只是一个哨兵对象,但由于我们将使用对象相等性来确定某个东西是否是最小值,所以这根本没有问题。)所需要的是被包装的对象是可比较的到一般自身的其他实例。

      一个缺点是当您调用getMinValue 时,您将收到编译器警告,因为返回类型将没有通用信息。可能有更优雅的方法来解决这个问题,但我现在想不出。

      总体而言,这个总体思路可能相当不错。但是,我真的应该强调:如果您尝试使用任何多态性或任何相互可比的类的混合,这绝对会失败。 Longs 和 Integers 在同一棵树上会彻底摧毁你。

      【讨论】:

        【解决方案6】:

        呃……又是什么问题?

        PriorityQueue 和所有Collections 一样,允许您使用一个对象的实例来从集合中remove 它。

        【讨论】:

        • 说得好。我建议 xhaker 检查 PriorityQueue 类的源代码以获取示例。
        【解决方案7】:

        这不取决于K是什么类型吗?

        Generic 的要点是 K 可以是任何类型(或某种类型的任何子类);为了能够调用 K 上的方法或访问它的属性,您需要使用通配符限制它的类型范围。

        【讨论】:

        • 这似乎是一个有效的东西——如果它是一个 int,我想要最低的值,但如果它是一个 long,我想要最低的 long 值。我不确定是否有一个简单的答案。如果您不使用泛型(仅传递一个数字或可比较的),您可能可以使用反射来解决大多数情况(我认为数字通常具有相同的 .MIN_VALUE 字段)
        • 比得上什么?它只能与您不知道的其他 K 相媲美。
        • 并不是所有的 Comparables 都有最大值或最小值(甚至是单个值,真的)。
        【解决方案8】:

        仅仅因为一个对象是可比较的并不意味着它必须具有最小值。 int 的最小值为 -(2^(31)) 的原因是因为您需要 1 位作为符号,因此 2^31 是可以存储的最大(或最小)整数。对于像字符串这样的东西,它没有任何意义,因为没有最大/最小可能的字符串,它是内存绑定的。

        【讨论】:

        • 肯定有一个最小的字符串:""。它只是最大的内存限制,
        • 排序规则是上下文相关的。我可以很容易地定义一个将空字符串放在最后的顺序。
        【解决方案9】:

        您可能必须创建一个接口“IInfinity”,并让 K 扩展 IInfinity,并让 IInfinity 拥有一个方法“getInfinityValue()”,然后在实现 IInfinity 的类中包装/扩展 Integer、Double、BigDecimal 等……嗯!

        【讨论】:

          【解决方案10】:

          基本上你希望任何类型的 K 实现一些静态函数,比如最低和最高,它们遵守标准的数学属性。

          我假设要使这种最低(或最高)的感觉可用,您会希望任何 Comparable 对象都具有这些方法。 (或静态字段)。如果您只对自己的自定义对象感兴趣,那么这样做的方法是让所有内容都继承自一个抽象数据类型,该数据类型为 MINVALUE 和 MAX_VALUE 声明了静态字段,然后您的类型变量将是 .如果您需要其他类的此功能,您将需要创建某种外部哈希图来跟踪不同类的这些属性(但这会变得非常难看)

          【讨论】:

            猜你喜欢
            • 2019-03-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-09-06
            • 1970-01-01
            • 1970-01-01
            • 2011-01-15
            • 1970-01-01
            相关资源
            最近更新 更多