2016-04-21 8 views
1

Это в основном следующее: question со вчерашнего дня. Я попытался реализовать «самый общий способ» (я мог подумать), чтобы создать «действительно» un-modifiable коллекции. Код ниже работает нормально; но это требует подавления предупреждений («rawtypes» и «unchecked»).Как избежать предупреждений о генераторах при использовании «сырых типов» в качестве статического поля/типа возврата?

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

(я видел это другое question, но я не уверен на 100%, если он действительно применим к моему коду, так как я не уверен, могу ли я записать интерфейс «Generator», не используя там сырой тип).

private interface Generator<T> { 
    T generateNewInstance(); 
} 

@SuppressWarnings("rawtypes") 
private final static Generator ListGenerator = new Generator<List>() { 
    @Override 
    public List generateNewInstance() { 
     return new ArrayList(); 
    } 
}; 

public static <T> List<T> unmodifiableListBasedOnCloneOf(List<T> elements) { 
    @SuppressWarnings("unchecked") 
    List<T> newInstance = makeNewInstanceOf(elements.getClass(), ListGenerator); 
    newInstance.addAll(elements); 
    return Collections.unmodifiableList(newInstance); 
} 

private static <T> T makeNewInstanceOf(Class<T> incomingClass, Generator<T> fallbackGenerator) { 
    try { 
     return (T) incomingClass.newInstance(); 
    } catch (IllegalAccessException | InstantiationException e) { 
     return fallbackGenerator.generateNewInstance(); 
    } 
} 
+2

Я не очень понимаю, что вы пытаетесь сделать здесь: если список заворачивают в 'unmodifiableList', почему имеет значение какой тип базовый список? Почему не 'Collections.unmodifiableList (новый ArrayList <> (elements))' достаточно? –

+0

Просто прочитайте мой другой вопрос. Дело в том, что это не так. Этот метод Collections добавляет ** декоратор ** в существующий список. Если вы получаете доступ к этому «первоначальному списку» через не оформленный интерфейс, вы можете изменить этот список; и тогда ваш предположительно не изменяемый список изменяется под обложкой. – GhostCat

+2

'Collections.unmodifiableCollection (новый ArrayList <> (элементы))' не является представлением 'elements': он копирует' elements' в новый список (точно так же, как вы здесь), а ссылка на этот новый список isn доступным ничем, кроме «немодифицируемого сотворения». –

ответ

4

Если вы делаете копию List<T> в новую ArrayList<T>, и передать эту эталонную встроенный в Collections.unmodifiableList, ничего, кроме неизменяемо декоратора имеет доступ к копии на изменить его:

List<String> original = new ArrayList<>(Arrays.asList("Hello", "World")); 

    // This simply decorates original, so updates to original are 
    // reflected in this list. 
    List<String> unmodifiableDecorator = Collections.unmodifiableList(original); 

    // The reference to the new ArrayList is scoped to the call to 
    // Collections.unmodifiableList, so nothing else can have a 
    // reference to it. 
    List<String> unmodifiableCopy = 
     Collections.unmodifiableList(new ArrayList<>(original)); 

    System.out.println("Before clear:"); 
    System.out.println(original); 
    System.out.println(unmodifiableDecorator); 
    System.out.println(unmodifiableCopy); 

    original.clear(); 

    System.out.println("After clear:"); 
    System.out.println(original); 
    System.out.println(unmodifiableDecorator); 
    System.out.println(unmodifiableCopy); 

Выход:

Before clear: 
[Hello, World] 
[Hello, World] 
[Hello, World] 
After clear: 
[] 
[] 
[Hello, World] 

Так что unmodifiableCopy не изменен и не может быть изменен, если вы не можете каким-то образом убедить unmodifiableList, чтобы дать вам ссылку на делегата.

Поскольку вы не можете изменить его, вам не нужно делать копию того же типа конкретного списка, что и список ввода. Просто сделайте его ArrayList, так как он имеет в значительной степени лучшую производительность чтения, которая может быть достигнута с помощью реализации .

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

public static <T> List<T> unmodifiableListBasedOnCloneOf(List<T> elements) { 
    return Collections.unmodifiableList(new ArrayList<>(elements)); 
} 
+0

Весь смысл моей реализации: что, если эта «поддержка lis» t "не является ArrayList? Но может быть LinkedList? Точка моей реализации состоит в том, чтобы использовать «ArrayList» только как резерв, когда код не может создать список того же характера, что и тот, который входит ... – GhostCat

+0

В чем преимущество наличия связанного списка, поддерживающего его ? Немодифицируемый список может использовать только методы, определенные в 'List'; единственными методами, для которых «LinkedList» обладает преимуществом, являются вставки или удаления среднего списка, которые не используются. Все методы только для чтения работают одинаково или хуже по сравнению с ArrayList. –

+0

Ну, пример о списке; но я имею в виду предоставить «действительно un-modifiable» обертки вокруг всех 5 методов из Коллекций. И там то же самое. И чтобы быть действительно ясным в этом: я не думаю, что ответ, который содержит в основном тот же код, что и вопрос, на самом деле не является ответом. Я знал, что могу сделать копию, используя ArrayList; но это не то, о чем я просил. – GhostCat

2

Не всегда можно избежать аннотации @SuppressWarnings. Я пытаюсь ограничить область действия локальной переменной.

Я пришел с этим:

private interface Generator<T> { 

    T generateNewInstance(); 
} 

private static class ListGenerator<T> implements Generator<List<T>> { 
    @Override 
    public List<T> generateNewInstance() { 
     return new ArrayList<>(); 
    } 
}; 

public static <T> List<T> unmodifiableListBasedOnCloneOf(List<T> elements) { 
    @SuppressWarnings("unchecked") 
    Class<List<T>> clazz = (Class<List<T>>)elements.getClass(); 
    List<T> newInstance = makeNewInstanceOf(clazz , new ListGenerator<T>()); 
    newInstance.addAll(elements); 
    return Collections.unmodifiableList(newInstance); 
} 

private static <T> T makeNewInstanceOf(Class<T> incomingClass, Generator<T> fallbackGenerator) { 
    try { 
     return (T) incomingClass.newInstance(); 
    } catch (IllegalAccessException | InstantiationException e) { 
     return fallbackGenerator.generateNewInstance(); 
    } 
} 
+0

Я вижу, что это спасает одно из предупреждений: при тонкой цене одного «нового» заявления (вероятно, это была преждевременная оптимизация, но я намеренно отложил решение, которое пытается свести к минимуму «действия», которые происходят для «хороший» случай, когда исключение не выбрасывается). – GhostCat

+0

'incomingClass.newInstance()' может обойти поддержку компилятора для отмеченных исключений. Если вы вызываете 'incomingClass.getConstructor(). newInstance()' он заставит вас поймать 'InvocationTargetException 'который будет обертывать исключения, созданные в конструкторе, позволяя вам обрабатывать их или использовать' fallbackGenerator', как вы сочтете нужным. –

 Смежные вопросы

  • Нет связанных вопросов^_^