2016-03-12 4 views
3

Я изучаю Java и сейчас читаю эффективную Java Joshua Bloch.Классы с параметрическим ключом для карты

В пункте 29 он обсуждает параметризованные ключи типа для карты для создания гетерогенной карты типа безопасного типа. Вот код:

class Favorites { 
    private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>(); 

    public <T> void putFavorite(Class<T> type, T instance) { 
     if (type == null) 
      throw new NullPointerException("Type is null"); 
     favorites.put(type, instance); 
    } 

    public <T> T getFavorite(Class<T> type) { 
     return type.cast(favorites.get(type)); 
    } 
} 

Он продолжает говорить, что

вредоносный клиент может легко повредить тип безопасности в Избранное , например, просто с помощью объекта класса в сыром виде. Но полученный код клиента генерирует непроверенное предупреждение, когда оно было составлено .

Я знаю, что Class<T> будет стерто до класса. Но я не уверен, как вредоносный клиент может нарушить безопасность типа во время компиляции. Я пробовал разные способы, но я всегда получал ошибку компилятора, как я и ожидал.

Может кто-нибудь, пожалуйста, скажите, что именно сказал Джошуа Блох в приведенной выше строке?

ответ

10

Необработанный тип - это тот, который не имеет общей информации. Вот как вы можете победить типобезопасность метода:

Favorites favorites = new Favorites(); 
favorites.putFavorite((Class)Integer.class, "foo"); // no compile error 

тогда это не будет компилировать:

favorites.putFavorite(Integer.class, "foo"); // compile error 

Поскольку тип параметра Class (а не Class<T>), общий метод параметр T не может быть определен, и вывод типа отключен для этого вызова. Это похоже на то, что код, вызывающий вызов, является предварительным дженериком, с которым java обратно совместима (игнорируя generics).

Вот как вы можете защититься от этой проблемы:

public <T> void putFavorite(Class<T> type, T instance) { 
    if (type == null) 
     throw new NullPointerException("Type is null"); 
    if (!type.isInstance(instance)) // add check for instance type 
     throw new IllegalArgumentException("Class/instance mismatch"); 
    favorites.put(type, instance); 
} 

или более жестоко (как вы не можете быть информативным с сообщением об ошибке), просто попытка бросание:

public <T> void putFavorite(Class<T> type, T instance) { 
    if (type == null) 
     throw new NullPointerException("Type is null"); 
    favorites.put(type, type.cast(instance)); // will throw ClassCastException 
} 

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

+2

Или в менее странном виде: 'Класс integerClass = Integer.class; favorites.putFavorite (integerClass, "foo"); ' –

+0

Perfect. Огромное спасибо. –

+0

Дело в том, что '' в подписи помогает избежать проблем, но для обеспечения чистых данных вам необходимо предотвратить коррупцию: реализация putFavorite должна была выполнить: 'избранное.put (type, type.cast (instance)) ' –

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

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