Определение параметров формального типа Java (Generics)

Я хотел бы определить универсальный тип, чей фактический параметр типа может быть только

  1. Один из числовых примитивных классов - оболочек ( Long, Integer, Float, Double)
  2. String

Я могу удовлетворить первое требование с таким определением

public final class MyClass<T extends Number> {
    // Implementation omitted
}

Но я не могу понять, как встретить их обоих. Я подозреваю, что это на самом деле невозможно, поскольку в AFAIK нет способа указать семантику "или" при определении параметра формального типа, хотя вы можете указать семантику "и", используя такое определение, как

public final class MyClass<T extends Runnable & Serializable > {
    // Implementation omitted
}

Ура, Дон

11.12.2008 20:26:14
Стирание типа вернуло бы его к объекту, если бы он существовал.
Loki 11.12.2008 20:48:50
5 ОТВЕТОВ

Интересный вопрос, он меня немного ошеломил. Однако, по-видимому, это невозможно. Я пробовал несколько разных хаков, но ни один из них не работал.

0
11.12.2008 20:36:10

Обобщения Java не поддерживают типы объединения (этот параметр может быть A ИЛИ B).

На связанной ноте, которая может быть интересна для некоторых, она поддерживает несколько границ, если вы хотите применить несколько ограничений. Вот пример из JDK, упомянутого в учебном пособии по Java :

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
11
11.12.2008 20:39:29
Разве это не плохой пример (я вижу, это от СОЛНЦА, а не от тебя)? <T расширяет Object & Comparable <? super T >> - это то же самое, что <T extends Comparable <? супер T >> не так ли? <T расширяет объект> ничего не значит.
Markus 12.12.2008 18:44:06
@ Маркус нет, это не плохой пример. Это не тоже самое. Без метода "extends Object" тип подписи Comparable (который не наследуется от объекта) вместо объекта, который требуется.
McTrafik 9.05.2012 22:49:19

Хотя генерики здесь не будут работать, базовый тип с производными типами for Numberи Stringwill. Так как универсальный тип в Objectлюбом случае был бы стерт , любая функциональность, которую вы бы там поместили, может перейти в абстрактный базовый класс. Вам, вероятно, понадобится только специфичный для типа метод доступа в подклассе, чтобы получить значение.

Также будьте осторожны с Numberклассом. Это не ограничивается боксом примитивных типов, так как любой может расширить его, например BigInteger.

2
11.12.2008 21:49:53

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

public final class MyClass<T> {
    public static MyClass<Integer> newInstance(int i) {
        return new MyClass<Integer>(i);
    }
    public static MyClass<String> newInstance(String s) {
        return new MyClass<String>(s);
    }
    //More factory methods...

    protected MyClass(T obj) {
        //...
    }
}

Или, если вам не нужен параметр конструктора, что-то вроде этого: public final class MyClass {public static MyClass newIntegerInstance () {return new MyClass (); } // ...}

Как сказал Эриксон, общая реализация в любом случае может полагаться только на Object, поэтому единственным ограничением является то, что вы можете создавать другие реализации для других типов, кроме примитива и String.

4
12.12.2008 09:27:17

Может быть, вы могли бы сделать следующее:

  1. Создайте MyClass<T>класс пакета по умолчанию, невидимый для других компонентов или, по крайней мере, только с ctors пакета по умолчанию, чтобы он не мог расширяться или создаваться вне пакета.
  2. Создайте два открытых класса в пакете MyClass<T>:
MyNumericClass<T extends Number> extends MyClass<T>
MyStringClass extends MyClass<String>

Таким образом, все подклассы MyClass будут ограничены теми, которые параметризованы с подклассом Number или String.

0
12.12.2013 13:03:46