Мой общий тест на Java не работает! - PullRequest
2 голосов
/ 01 февраля 2011

Я занимаюсь изучением Java, особенно в области дженериков.

Я довольно хорошо знаком с дженериками в C #, но в Java это совсем другая история.

Я использовал несколько примеров, которые отлично работали для тестирования, и я в состоянии воспроизвести большую часть своего кода C # на Java просто отлично.

Однако, когда я пробую следующий пример, он не работает:

private static <T> void swapKundeData(ArrayList<T> data, int index1, int index2) {

    T temporary = (T) data.get(index1);

    data.set(index1, data.get(index2)); //Does not compile
    data.set(index2, temporary); //Does not compile

}

Я получаю ошибку:

Набор методов (int, capture # 5-of? Extends ExtendTest) в типе ArrayList не применим для аргументов (int, ExtendTest)

Эквивалент этого прекрасно работает в C # - так что же происходит?

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

Ответы [ 6 ]

6 голосов
/ 01 февраля 2011

Ну, например, я бы использовал

List<Kunde> 

вместо

ArrayList<?>

так как вы все равно разыгрываете Кунде:).

Причина, по которой это не работает, заключается в том, что вы не знаете тип передаваемых объектов. Так что если вы установите Kunde, который может быть неправильного типа (поскольку с ArrayList <?> Вы можете передать ArrayList и установить Kunde для этого будет неправильный тип).

Другая возможность:

private static <T> void swapData(List<T> data, int index1, int index2) {

    T temporary = data.get(index1);

    data.set(index1, data.get(index2)); //Does compile
    data.set(index2, temporary); //Does compile

}

И чтобы завершить мою напыщенную речь, просто используйте метод обмена Коллекций.

http://download.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html#swap(java.util.List, int, int)

2 голосов
/ 01 февраля 2011

Если вы знаете, что ваш ArrayList содержит Kunde объектов, вам следует объявить аргумент метода ArrayList<Kunde>; нет необходимости использовать подстановочный знак. И, как вы можете видеть, это вызывает ошибки типа во время компиляции.

См. http://download.oracle.com/javase/tutorial/extra/generics/wildcards.html для полного объяснения проблемы.

1 голос
/ 01 февраля 2011

Я отмечаю, что вопрос был отредактирован так, что предыдущие ответы не имеют особого смысла.

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

public static void swapKundeData(List<?> data, int index1, int index2) {

Но вы хотите реализовать:

public static <T> void swapKundeData(List<T> data, int index1, int index2) {

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

public static void swapKundeData(List<?> data, int index1, int index2) {
    swapKundeDataImpl(data, index1, index2)
}

private static <T> void swapKundeDataImpl(List<T> data, int index1, int index2) {

(здесь я предполагаю, что "кунде" - это не грубое слово.)

1 голос
/ 01 февраля 2011

Проблема была в Eclipse.

Я не сохранил файл, поэтому, по-видимому, ничего не было перекомпилировано.

Вау, я действительно впечатлен неспособностями и неприятностями IDE, такими как скорость.

Ну хорошо.

1 голос
/ 01 февраля 2011

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

Вот почему использование подстановочного знака ? очень редко подходит. Почти во всех случаях вы должны использовать конкретный тип или именованный ограниченный тип:

private static void swapKundeData(List<Kunde> data, int index1, int index2) {
    Kunde temporary = data.get(index1);
    data.set(index1, data.get(index2));
    data.set(index2, temporary);
}

Обратите внимание на использование интерфейса List, который делает код гораздо более гибким в отношении того, что он принимает.

private static <T> void swap(List<T> data, int index1, int index2) {
    T temporary = data.get(index1);
    data.set(index1, data.get(index2));
    data.set(index2, temporary);
}

Это обобщенное решение действительно , которое безопасно для типов, но не должно знать, какой тип элементов списка. Вы на самом деле не получаете никакой безопасности типов, используя здесь Generics (Object будет так же хорошо), но вы можете, например, вернуть один из замененных элементов, и компилятор узнает, что возвращаемое значение того же типа, что и элементы списка.

0 голосов
/ 01 февраля 2011

Подводя итог сказанному Оли, вы не можете присвоить коллекцию "неизвестного типа" '?' потому что ява не знает, что там делать. Однако, поскольку каждый «неизвестный тип» все еще является объектом, можно безопасно вызывать методы «getter» для него, потому что они всегда будут возвращать объект типа Object.

...