Можно улучшить этот сценарий Java Generics [duplicate]

Хехех, странно видеть, что я пытаюсь дать лучшее и более простое объяснение после 2600+ голосов на том, что было отмечено как правильный ответ от Grew Hewgill.

Здесь мы идем ...

На мой взгляд, вы лучше поймете и запомните нотацию нотации струны Python, если вы посмотрите на нее следующим образом (читайте дальше).

Давайте работать со следующей строкой. .

azString = "abcdefghijklmnopqrstuvwxyz"

Для тех, кто не знает, вы можете создать любую подстроку из azString, используя нотацию azString[x:y]

. Исходя из других языков программирования, здравый смысл скомпрометирован. Что такое x и y?

Мне пришлось сесть и запустить несколько сценариев в поисках метода запоминания, который поможет мне запомнить, что такое x и y, и помочь мне правильно отрезать строки с первой попытки.

Мой вывод состоит в том, что x и y следует рассматривать как граничные индексы, которые окружают строки, которые мы хотим добавить. Таким образом, мы должны видеть выражение как azString[index1, index2] или даже более ясно, как azString[index_of_first_character, index_after_the_last_character].

Вот пример визуализации этого ...

Letters a b c d e f g h i j ... ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ Indexes 0 1 2 3 4 5 6 7 8 9 ... | | cdefgh index1 index2

Итак, все, что вам нужно сделать, если установить index1 и index2 в значения, которые будут окружать нужную подстроку. Например, чтобы получить подстроку «cdefgh», вы можете использовать azString[2:8], потому что индекс в левой части «c» равен 2, а тот, который имеет правый размер «h», равен 8.

Помните, что мы устанавливаем границы.

Этот трюк работает все время и легко запоминается.

Hopefuly это поможет.

46
задан Zhao Yi 15 July 2012 в 09:21
поделиться

3 ответа

Вы не можете. Java не разрешает общие типы для констант перечисления. Они разрешены для типов перечислений, хотя:

public enum B implements A<String> {
  A1, A2;
}

. Что вы могли бы сделать в этом случае, либо иметь тип перечисления для каждого родового типа, либо «поддельный» с перечислением, просто сделав его классом :

public class B<T> implements A<T> {
    public static final B<String> A1 = new B<String>();
    public static final B<Integer> A2 = new B<Integer>();
    private B() {};
}

К сожалению, оба они имеют недостатки.

46
ответ дан John Kugelman 27 August 2018 в 23:45
поделиться

Если принимается JEP 301: Enhanced Enums , , тогда вы сможете использовать такой синтаксис (взять из предложения):

enum Primitive<X> {
    INT<Integer>(Integer.class, 0) {
        int mod(int x, int y) { return x % y; }
        int add(int x, int y) { return x + y; }
    },
    FLOAT<Float>(Float.class, 0f)  {
        long add(long x, long y) { return x + y; }
    }, ... ;

    final Class<X> boxClass;
    final X defaultValue;

    Primitive(Class<X> boxClass, X defaultValue) {
        this.boxClass = boxClass;
        this.defaultValue = defaultValue;
    }
}
1
ответ дан ArtB 27 August 2018 в 23:45
поделиться

Как разработчики Java, разрабатывающие определенные API, мы часто сталкиваемся с этой проблемой. Я повторил свои собственные сомнения, когда столкнулся с этим сообщением, но у меня есть подробное обходное решение:

// class name is awful for this example, but it will make more sense if you
//  read further
public interface MetaDataKey<T extends Serializable> extends Serializable
{
    T getValue();
}

public final class TypeSafeKeys
{
    static enum StringKeys implements MetaDataKey<String>
    {
        A1("key1");

        private final String value;

        StringKeys(String value) { this.value = value; }

        @Override
        public String getValue() { return value; }
    }

    static enum IntegerKeys implements MetaDataKey<Integer>
    {
        A2(0);

        private final Integer value;

        IntegerKeys (Integer value) { this.value = value; }

        @Override
        public Integer getValue() { return value; }
    }

    public static final MetaDataKey<String> A1 = StringKeys.A1;
    public static final MetaDataKey<Integer> A2 = IntegerKeys.A2;
}

. В этот момент вы получаете преимущество от истинного постоянного значения enum (и все преимущества, которые идут с этим), а также уникальная реализация interface, но у вас есть глобальная доступность, желаемая enum.

Ясно, что это добавляет многословие, что создает потенциал для ошибок копирования / вставки. Вы можете сделать enum s public и просто добавить дополнительный слой к их доступу.

Конструкции, которые имеют тенденцию использовать эти функции, как правило, страдают от хрупких реализаций equals, потому что они обычно связаны с другое уникальное значение, такое как имя, которое может быть невольно дублировано в кодовой базе для аналогичной, но другой цели. Используя enum s по всей доске, равенство - это халява, которая невосприимчива к такому хрупкому поведению.

. Основным недостатком такого, как система, помимо многословия, является идея преобразования вперед и назад между глобально уникальные ключи (например, маршалинг и JSON). Если они являются просто ключами, то их можно безопасно восстановить (продублировать) за счет потери памяти, но используя то, что было ранее слабостью - equals - в качестве преимущества.

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

public abstract class BasicMetaDataKey<T extends Serializable>
     implements MetaDataKey<T>
{
    private final T value;

    public BasicMetaDataKey(T value)
    {
        this.value = value;
    }

    @Override
    public T getValue()
    {
        return value;
    }

    // @Override equals
    // @Override hashCode
}

public final class TypeSafeKeys
{
    public static final MetaDataKey<String> A1 =
        new BasicMetaDataKey<String>("value") {};
    public static final MetaDataKey<Integer> A2 =
        new BasicMetaDataKey<Integer>(0) {};
}

Обратите внимание, что каждый экземпляр использует анонимную реализацию, но ничего не нужно для его реализации, поэтому {} пустые. Это и запутывает, и раздражает, но работает, если ссылки на экземпляры предпочтительнее, а помехи сведены к минимуму, хотя это может быть немного загадочно для менее опытных разработчиков Java, что затрудняет его поддержку.

Наконец, единственный способ обеспечить глобальную уникальность и переназначение - быть немного более творческим в том, что происходит. Наиболее распространенное использование для общедоступных интерфейсов, которые я видел, для котей MetaData, которые имеют тенденцию смешивать множество разных значений с разными типами (T в каждом ключе):

public interface MetaDataKey<T extends Serializable> extends Serializable
{
    Class<T> getType();
    String getName();
}

public final class TypeSafeKeys
{
    public static enum StringKeys implements MetaDataKey<String>
    {
        A1;

        @Override
        public Class<String> getType() { return String.class; }

        @Override
        public String getName()
        {
            return getDeclaringClass().getName() + "." + name();
        }
    }

    public static enum IntegerKeys implements MetaDataKey<Integer>
    {
        A2;

        @Override
        public Class<Integer> getType() { return Integer.class; }

        @Override
        public String getName()
        {
            return getDeclaringClass().getName() + "." + name();
        }
    }

    public static final MetaDataKey<String> A1 = StringKeys.A1;
    public static final MetaDataKey<Integer> A2 = IntegerKeys.A2;
}

Это обеспечивает такую ​​же гибкость, как и первый вариант, и обеспечивает механизм получения ссылки посредством отражения, если это становится необходимым позже, поэтому избегая необходимости в последующем. Он также избегает многих ошибок, связанных с ошибкой копирования / вставки, которые первый параметр предоставляет, поскольку он не будет компилироваться, если первый метод неверен, а второй метод не нужно изменять. Единственное замечание заключается в том, что вы должны убедиться, что enum s предназначены для использования таким образом public, чтобы избежать доступа к ошибкам доступа, поскольку они не имеют доступа к внутреннему enum; если вы не хотите, чтобы эти MetaDataKey проходили через маршалированный провод, то их можно было скрывать из внешних пакетов, чтобы их автоматически отменить (во время маршалинга, рефлексивно проверить, доступен ли enum, и если это не так, то игнорируйте ключ / значение). Нет ничего выигранного или потерянного, сделав его public, за исключением предоставления двух способов доступа к экземпляру, если поддерживаются более очевидные static ссылки (поскольку экземпляры enum просто так или иначе).

Я просто хочу, чтобы они сделали это так, чтобы enum s могли расширять объекты на Java. Может быть, в Java 9?

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

27
ответ дан pickypg 27 August 2018 в 23:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: