简体   繁体   English

Java泛型和无限(可比)

[英]Java Generics and Infinity (Comparable)

With the type Integer you can do this: 使用Integer类型,您可以执行以下操作:

int lowest = Integer.MIN_VALUE;

What can I do if I use generics? 如果我使用泛型,我该怎么办?

K lowest = <...>;

I need this in order to implement something similar to a PriorityQueue. 我需要这个来实现类似于PriorityQueue的东西。 I have access to a node I want to remove from the queue, but it is not the min. 我可以访问我想要从队列中删除的节点,但它不是min。

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

I am stuck on the first step. 我坚持第一步。 The only thing I can do is set the key of the node to the current min. 我唯一能做的就是将节点的键设置为当前最小值。 Not sure it is enough. 不确定它是否足够。

This doesn't make any sense... 这没有任何意义......

Given that you don't know what K is at that point, (ie You're implementing it generically... duh!) you can't specify a min/max bound for it. 鉴于你不知道K在那一点上是什么,(即你一般都是在实现它......呃!)你不能指定它的最小/最大界限。

in a case where K could be a int, long, string OR object, you couldn't sensibly guess to use 在K可以是int,long,string OR对象的情况下,你无法明智地猜测使用它

Integer.MIN_VALUE, "" OR NULL. Integer.MIN_VALUE,“”OR NULL。

I guess what you're looking for is a K.MIN_VALUE_OF_EVENTUAL_TYPE but that doesn't exist. 我猜你要找的是K.MIN_VALUE_OF_EVENTUAL_TYPE但是不存在。

There is no generic form of MIN_VALUE or MAX_VALUE for all Comparable types. 对于所有可比较类型,没有通用形式的MIN_VALUEMAX_VALUE

Think about a Time class that implements comparable. 想想实现可比较的Time类。 There is no MAX_VALUE for Time even though it is Comparable. 即使它是可比较的,时间也没有MAX_VALUE

I am trying to imagine what scenario would require such behavior. 我试图想象什么情况需要这样的行为。 This is the best I can come up with... 这是我能想到的最好的......

WARNING: This code is dangerous. 警告:此代码很危险。 Please be merciful to me for posting such an abomination. 发表这样的憎恶,请怜悯我。 It is only a proof of concept. 这只是一个概念证明。

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

And then... 然后...

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

You can make a wrapper class that "adds" a minimum and maximum value to all types. 您可以创建一个包装类,为所有类型“添加”最小值和最大值。 It just has two static instances that represent minimum and maximum, and then other instances wrap some other value of some type. 它只有两个表示最小值和最大值的静态实例,然后其他实例包含某些类型的其他值。 When we do a comparison, we check if one of the things is the minimum or maximum, and return the proper result; 当我们进行比较时,我们检查其中一个是最小值还是最大值,并返回正确的结果; and otherwise we just do the same comparison as the underlying type. 否则我们只是做与基础类型相同的比较。 Something like this: 像这样的东西:

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

er... what's the problem again? 呃......又是什么问题?

PriorityQueue , like all Collections , allows you to use an instance of an object to remove it from the collection. 与所有集合一样PriorityQueue允许您使用对象的实例其从集合中删除

Uh doesn't this depend on what type K is? 呃这不取决于K是什么类型的?

The point of Generics is that K can be any type (or any subclass of a certain type); 泛型的观点是K可以是任何类型(或某种类型的任何子类); in order to be able to call methods on K or access properties of it, you need to restrict it's type bounds with wildcards. 为了能够在K上调用方法或访问它的属性,您需要使用通配符限制它的类型边界。

just because an object is a comparable does not mean it has to have a minimum value. 仅仅因为一个对象是可比较的并不意味着它必须具有最小值。 The reason int has a min value of -(2^(31)) is because you need 1 bit for a sign, so 2^31 is the largest (or smallest) possible integer that can be stored. int的最小值为 - (2 ^(31))的原因是因为符号需要1位,所以2 ^ 31是可以存储的最大(或最小)可能的整数。 For things like string, it does not make any sense since there is no largest/smallest possible string, it is memory bound. 对于像字符串这样的东西,它没有任何意义,因为没有最大/最小的可能字符串,它是内存绑定的。

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

Basically you want any type K to implement some static functions say lowest and highest which obey the standard mathematical properties. 基本上你希望任何类型K实现一些静态函数,比如最低和最高,遵循标准的数学属性。

I assume that for this sense of lowest (or highest) to be usable you would want any Comparable object to have these methods. 我假设对于这种最低(或最高)可用的感觉,你会希望任何Comparable对象都有这些方法。 (or static fields). (或静态字段)。 If you are only interested in your own custom objects, the way to do this would be to have everything inherit from an abstract data type which declared static fields for MINVALUE and MAX_VALUE and then your type varaibles would be . 如果您只对自己的自定义对象感兴趣,那么执行此操作的方法是将所有内容都从一个抽象数据类型继承,该抽象数据类型声明了MINVALUE和MAX_VALUE的静态字段,然后是类型变量。 If you need this functionality for other classes you will need to cre4ate some sort of external hashmap which tracks these properties for different classes (but that would get pretty ugly) 如果你需要为其他类提供这个功能,你需要创建一些外部hashmap来跟踪不同类的这些属性(但这会非常难看)

Consider not making K a generic, but using an interface that wraps the primitive wrapper (a double wrapper!). 考虑不要使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);
        }
    }

}

Briefly, the idea is that whenever a new class is instantiated, a minimum value is created and put into a static hashmap that stores the minimum values for each class. 简而言之,这个想法是每当实例化一个新类时,就会创建一个最小值并将其放入一个静态hashmap中,该hashmap存储每个类的最小值。 (In fact, these values are NOTHING at all, just a sentinel object, but since we will use object equality to determine if something is the min value, this is no problem at all.) All that's necessary is that the wrapped object be comparable to other instances of itself in general. (事实上​​,这些值根本就没有,只是一个标记对象,但由于我们将使用对象相等来确定某些东西是否为最小值,这根本不是问题。)所有必要的是包装对象是可比较的一般而言,对于其他自身的实例。

One drawback is that when you call getMinValue you will have compiler warnings, since the return type will have no generic information. 一个缺点是,当您调用getMinValue时,您将getMinValue编译器警告,因为返回类型将没有通用信息。 There may be a more elegant way around this, but I can't think of it right now. 可能有更优雅的方式,但我现在想不到它。

This general idea might be rather nice overall. 总体思路可能相当不错。 However, I should really stress: this will absolutely break if you try it with any polymorphism or any mixing of mutually comparable classes. 但是,我应该强调:如果你尝试使用任何多态或任何相互比较的类混合,这绝对会破坏。 Long s and Integer s in the same tree will completely destroy you. 同一棵树中的Long s和Integer将完全摧毁你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM