2015-03-18 2 views
0

Предположит, у меня есть этот код:Как можно злоупотреблять назначением без явно указанного общего типа?

private Hashtable items = new Hashtable(); 

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

Гораздо лучшим решением будет либо:

private Hashtable<String,String> items = new Hashtable<String,String>(); 

или (если я не уверен, о типе)

private Hashtable<?,?> items = new Hashtable<?,?>(); 

Каковы последствия не предоставления типа явно и может это злоупотреблять, скажем, с точки зрения безопасности? Может ли это быть пойманным в результате теста (нужно ли использовать рефлексию?) И как?

+0

«* Eclipse выдаст предупреждение для такого назначения, потому что это неконтролируемая, небезопасная операция» * Компилятор Java выдаст предупреждение типа raw, а не непроверенную/небезопасную операцию. – m0skit0

ответ

1

Используя необработанный тип, вы не можете компилятор запретить вам добавлять на карту старый ключ и значение. Это может быть хорошо, если ваши ключи и значения будут Object с, но это не очень распространено в моем опыте.

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

Map<String, String> genericMap = new HashMap<>(); 
genericMap.put(new Object(), new Object()); // compiler error. 

Однако, если вы должны были написать:

Map rawMap = genericMap; 
rawMap.put(new Object(), new Object()); // fine. 

Так что теперь в основном все ставки выключены, как к тому, что содержится в этой карте. Если вы передаете genericMap к отдаленному методу, который ожидается в Map<String, String> и собираетесь потреблять значения из него, вы собираетесь получить отказ во время выполнения, вероятно, ClassCastException:

import java.util.HashMap; 
import java.util.Map; 

class DontDoThis { 
    @SuppressWarnings("unchecked") 
    public static void main(String[] args) { 
    Map<String, String> genericMap = new HashMap<>(); 
    Map rawMap = genericMap; 
    rawMap.put(new Object(), new Object()); 
    useMap(genericMap); 
    } 

    private static void useMap(Map<String, String> map) { 
    for (String key : map.keySet()) {} // ClassCastException. 
    } 
} 

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

Map<?, ?> wildcardMap = genericMap; 
genericMap.put("key1", "value1"); // fine. 
wildcardMap.put("key", "value"); // compiler error. 

Вы можете, однако, по-прежнему использовать значение из wildcardMap; все, что вы можете знать о них является то, что значения являются подтипами Object:

for (Map.Entry<?, ?> entry : wildcardMap.entrySet()) { 
    Object key = entry.getKey(); 
    Object value = entry.getValue(); 

    // Use key and value somehow. 
} 

Что касается вопроса о том, как она может быть поймана в тесте - вы не должны писать тесты для такого рода вещи - успешная компиляция - это ваш тест!

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

0

Дженерики в Java - это концепция времени компиляции, они не существуют во время выполнения. Это называется стиранием типа. Поэтому с точки зрения безопасности они не могут злоупотребляться в запущенном приложении. Я не знаю точно, что вы хотите проверить с помощью отражения в тесте, но вы можете получить информацию о дженериках только в нескольких случаях. Reflection generics

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