2009-04-29 2 views
5

С типа Integer вы можете сделать это:Java Дженерики и Бесконечность (Сопоставимые)

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. 

Я застрял на первом шаге. Единственное, что я могу сделать, это установить ключ узла на текущий мин. Не уверен, что этого достаточно.

+0

Возможно, вы сможете предложить пример кода, иллюстрирующий, как вы хотите использовать K? –

+0

Можете ли вы немного разобраться? Некоторый соответствующий код будет приятным. –

+0

Кстати, объектные версии числовых литералов расширяют java.lang.Number. К сожалению, Number не имеет ничего подобного getMaximumValue(). – Powerlord

ответ

4

Это не имеет никакого смысла ...

Учитывая, что вы не знаете, что K является в этой точке (т.е. вы реализуете это в общем ... хм!) Вы не можете укажите для него минимальную/максимальную границу.

в случае, когда K может представлять собой INT, длинный, строка или объект, вы не могли разумно догадаться использовать

Integer.MIN_VALUE «» ИЛИ NULL.

Я предполагаю, что вы ищете K.MIN_VALUE_OF_EVENTUAL_TYPE, но этого не существует.

+2

Это может быть кто-то, исходящий из фона C++, где тривиально просто использовать numeric_limits :: max и numeric_limits :: мин. Это позволяет вам писать код, который обрабатывает символы, удваивает, ints, 64-битные int или даже пользовательские числовые классы. – Eclipse

+0

Я наткнулся на это во время поиска той же идеи, и вот мой прецедент: 1. У меня есть интерфейс со следующим методом 'Comparable getGroupIndex (String groupName)' этот метод возвращает 'null', если' groupName' неизвестно. 2. В классе, где я вызываю метод выше, если возвращаемое значение равно «null», я хочу поместить его в конец списка (рассматривайте его как возвращаемое значение максимального значения Comparable). Я собираюсь вместо этого решить это, вернув максимальное значение вместо нуля, но просто хотел пролить свет на прецедент. – mwakerman

1

Это не зависит от типа K.

Пункт Generics состоит в том, что K может быть любым типом (или любым подклассом определенного типа); для того, чтобы иметь возможность вызывать методы на K или свойства доступа к нему, вам нужно ограничить ограничения типа с помощью подстановочных знаков.

+0

Ну, K сравнимо. –

+1

Кажется, что нужно иметь правильную вещь - если это int, я хочу самое низкое значение, но если оно длинное, я хочу наименьшее длинное значение. Я не уверен, что есть простой ответ. Если вы не использовали Generics (просто передавая число или сопоставимые), вы, вероятно, могли бы использовать рефлексию для решения большинства случаев (у чисел, как правило, есть то же самое поле .MIN_VALUE, которое я думаю) –

+0

Сопоставимо с чем? Это только сопоставимо с другими К, которые вы не знаете. –

4

Для всех сравнимых типов нет общей формы MIN_VALUE или MAX_VALUE.

Подумайте о классе Time, который реализует сравнимые характеристики. Существует нет MAX_VALUE для Time, хотя он является сравнимым.

1

только потому, что объект сопоставим, не означает, что он должен иметь минимальное значение. Причина int имеет минимальное значение - (2^(31)), потому что вам нужен 1 бит для знака, поэтому 2^31 - это самое большое (или самое маленькое) возможное целое число, которое можно сохранить. Для таких вещей, как строка, это не имеет никакого смысла, поскольку нет самой большой/наименьшей возможной строки, она связана с памятью.

+0

Конечно, существует наименьшая возможная строка: "". Это только самое большое, связанное с памятью, – Eclipse

+0

Правила сортировки являются контекстуальными. Я мог бы так же легко определить порядок, который пуст пустые строки. – erickson

1

Возможно, вам потребуется создать интерфейс «IInfinity», а K расширяет IInfinity и IInfinity, чтобы иметь метод «getInfinityValue()», а затем обернуть/расширить Integer, Double, BigDecimal и т. Д. В классе, который реализует IInfinity ... и тьфу!

1

В принципе, вы хотите, чтобы любой тип K выполнял некоторые статические функции, говорящие наименьшие и самые высокие, которые подчиняются стандартным математическим свойствам.

Я предполагаю, что для того, чтобы этот смысл наименьшего (или самого высокого) был применим, вы хотели бы, чтобы любой объект Comparable имел эти методы. (или статические поля). Если вас интересуют только ваши собственные пользовательские объекты, способ сделать это будет иметь все наследование от абстрактного типа данных, который объявлял бы статические поля для MINVALUE и MAX_VALUE, а затем ваши типы varaibles.Если вам нужна эта функциональность для других классов, вам нужно будет создать какой-то внешний хэш-файл, который отслеживает эти свойства для разных классов (но это будет довольно уродливо)

4

Я пытаюсь представить, какой сценарий потребует такого поведения. Это лучшее, что я могу придумать ...

ВНИМАНИЕ: Этот код является опасным. Пожалуйста, будьте милостивы ко мне за такую ​​мерзость. Это всего лишь доказательство концепции.

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

Хорошо, это совершенно странно. Мы сделали тот же комментарий по этому вопросу в течение секунды друг от друга, а затем мы ждали 20 минут и отправили почти такой же код за 15 секунд друг от друга. Думаю, мне нужно немного отдохнуть ... –

+0

@mmyers: Weird! Я думаю, что сам займу долгий перерыв. :) –

+1

Я не уверен, что хуже, хотя: мое использование рефлексии для поиска конструктора (для потенциально нетривиального класса) или для вашего отличного от K до K. –

1

Рассматривают не делает 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); 
     } 
    } 

} 

Вкратце, идея заключается в том, что всякий раз, когда новый класс экземпляра, минимальное значение создается и помещается в статическую HashMap, которая хранит минимальные значения для каждого класса. (Фактически эти значения НИЧЕГО вообще, просто объект-дозор, но поскольку мы будем использовать равенство объектов, чтобы определить, является ли что-то минимальным значением, это не проблема вообще.) Все, что необходимо, это то, что обернутый объект будет сопоставимым к другим экземплярам себя в целом.

Один из недостатков заключается в том, что при вызове getMinValue у вас будут предупреждения о компиляторе, так как тип возврата не будет иметь общей информации. Там может быть более элегантный способ, но я не могу думать об этом прямо сейчас.

Эта общая идея может быть довольно приятной в целом. Тем не менее, я должен действительно подчеркнуть: это будет абсолютно нарушено, если вы попробуете его с любым полиморфизмом или любым смешением взаимно сопоставимых классов. Long s и Integer s в том же дереве полностью уничтожит вас.

2

er ... в чем проблема снова?

PriorityQueue, как и все Collections, позволяет использовать экземпляр объекта remove из коллекции.

+0

Ха-ха. Фокус :-) – KarlP

+0

Хорошо сказано. Я рекомендую, чтобы xhaker проверил исходный код для класса PriorityQueue для примера. –

2

Вы можете создать класс-оболочку, который «добавляет» минимальное и максимальное значение для всех типов. Он просто имеет два статических экземпляра, представляющих минимальный и максимальный, а затем другие экземпляры переносят другое значение какого-либо типа. Когда мы проводим сравнение, мы проверяем, является ли одна из вещей минимальной или максимальной и возвращает правильный результат; и в противном случае мы просто делаем то же самое сравнение, что и базовый тип. Что-то вроде этого:

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); 
    } 
} 
Смежные вопросы