Можно ли использовать дженерики в списках в Java 1.4? - PullRequest
5 голосов
/ 12 июня 2011

Я должен использовать Java 1.4, и я использую структуры Arraylist.Теперь мне нужно сделать ре-факторинг, и это поможет, если я смогу использовать Generics.В настоящее время у меня есть код, подобный этому

ArrayList rows = new ArrayList();

, который является простым ArrayList.Но теперь переменная "rows" становится все более сложной и требует определения класса "Row".Теперь я хочу сделать что-то похожее на то, что вы видите в J2SE 1.5

ArrayList<Row> rows = new ArrayList();

Трал через Google не дает никаких ответов без какого-либо изощренного использования сторонних решений.Как мой код должен измениться, чтобы соответствовать этому в 1.4, без использования сторонних решений / проектов с открытым исходным кодом (если это возможно)?

Ответы [ 5 ]

9 голосов
/ 12 июня 2011

Обобщения были введены в JDK 1.5. Таким образом, вы не можете использовать их в 1.4. Тем не менее, вы можете использовать компилятор JDK 1.5, но нацелитесь на 1.4 с вашими классами с опцией -target 1.4 javac, оставив опцию -source 1.5, чтобы указать, что ваш источник 1.5 совместим. В этом случае вы можете использовать дженерики, так как они не должны влиять на классы результатов.

См. Раздел «Параметры кросс-компиляции»

4 голосов
/ 12 июня 2011

Обобщения имеют тенденцию решать проблему того, что я считаю «наивными приведениями» в Java 1.4 или более ранних версиях при работе с коллекциями. В Java 1.5+ строка, которую вы поместили:

ArrayList<Row> rows = new ArrayList();

выдаст предупреждение, правильный общий код:

ArrayList<Row> rows = new ArrayList<Row>();

Это говорит компилятору, что ваш объект ArrayList должен содержать только тип Row.

Однако, поскольку Java 1.5 обратно совместима с огромными наборами библиотек, которые не содержат этот синтаксис, а скорее ваш предыдущий код:

ArrayList rows = new ArrayList();

Дженерики, очевидно, не будут работать с этими старыми библиотеками - поэтому дженерики являются только опцией времени компиляции - классы 1.5 и 1.4 фактически эквивалентны (за исключением любых внутренних методов рефакторинга / новых методов, добавленных позже), потому что они на самом деле реализации ArrayList, которые обрабатывают любой тип объекта.

Код 1.5 просто добавляет прямое приведение для вас.

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

for(Iterator rowIterator = rows.iterator(); rowIterator.hasNext(); ) {
    Row row = (Row) rowIterator.next();
    // Do something with the row.
}

Код Java 1.5 в точности эквивалентен наивной версии. Принимается тот факт, что вы сообщаете компилятору, что он является строкой и выполняет этот код за вас. Итак, преимущества синтаксического сахара более приятны (при этом используется новый синтаксис для каждого цикла, но генерируется тот же код, что и в предыдущем цикле):

for(Row row : rows) {
   // Do something with the row
}

Итак, если вы хотите использовать ArrayList, содержащий только строки, вы все равно можете это сделать. Но нет никакого способа заставить компилятор проверить , что ArrayList содержит только все строки (хотя, хотя компилятор обеспечивает эту проверку, все еще можно отправить в ArrayList, который содержит другие типы объектов, поскольку, опять же, ArrayList все еще действительно обрабатывает тип Object, а универсальные значения стираются во время выполнения - все, что остается, - это наивный код приведения, который вы больше не видите).

Не наивный вариант состоит в том, чтобы проверять каждый экземпляр и генерировать исключение ClassCastException самостоятельно с информативным сообщением (вместо того, чтобы программа выдавала его с сообщением по умолчанию):

for(Iterator rowIterator = rows.iterator(); rowIterator.hasNext(); ) {
    Object shouldBeRow = rowIterator.next();
    if(!(shouldBeRow instanceof Row)) {
        throw new ClassCastException("The object " + shouldBeRow + " is not an instance of Row - only Rows should be present in the list!");
    }
    Row row = (Row) shouldBeRow;
    // Do something with the row.
}

Однако, как правило, никто не делает этого - хорошая документация может спровоцировать эту проблему, так как это накладывает бремя обеспечения правильной коллекции на вызывающую сторону, и, таким образом, вы можете просто вызвать ClassCastException, выдаваемый JVM.

2 голосов
/ 12 июня 2011

Да, вы можете. Используйте компилятор 1.5 и используйте

javac -target jsr14 ............

Это сгенерирует классы java 1.4, но позволит использовать дженерики.

Этот переключатель можно использовать только для видимых функций 1.5. Например, вы не можете использовать Enums или новые методы, введенные в 1.5. Но дженерики хороши, так как они на самом деле отсутствуют в байт-коде.

0 голосов
/ 12 июня 2011

Нет, вы не можете использовать их в JDK 1.4. Они были введены в JDK1,5

0 голосов

Все, что вам нужно сделать, это разыграть их. Это может заслужить исключение времени выполнения, если вы добавите в список «неправильные» типы.

Row arow = (Row) rows.get(0);

for ($i=0; i<rows.size(); $i++){
    Row element = (Row) rows.get($i);
    element.printCells();
    (...)
}
...