Определение параметра формального типа 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
}

Ваше здоровье, Дон

Стирание типа вернет его обратно к объекту, если он существует.

Loki 11.12.2008 23:48
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
8
1
6 201
5

Ответы 5

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

Дженерики Java не поддерживают типы объединения (этот параметр может быть A OR B).

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

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)

Разве это не плохой пример (я вижу, это от SUN, а не ваш)? <T расширяет Object & Comparable <? super T >> - это то же самое, что <T extends Comparable <? super T >>, не так ли? <T extends Object> ничего не значит.

Markus 12.12.2008 21:44

@Markus нет, это неплохой пример. Это не одно и то же. Без типа сигнатуры метода extends Object является Comparable (который не наследуется от объекта) вместо Object, который требуется.

McTrafik 10.05.2012 02:49

В то время как обобщенные типы здесь не работают, базовый тип с производными типами для Number и String будет. Поскольку универсальный тип в любом случае был бы удален в Object, любые функции, которые вы бы туда поместили, могут быть переданы в абстрактный базовый класс. Скорее всего, для получения значения вам понадобится только метод доступа, зависящий от типа, в подклассе.

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

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

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 () { вернуть новый MyClass (); } // ... }

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

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

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

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

Другие вопросы по теме