Безопасность типов: непроверенное приведение из Object в ArrayList<MyVariable>
Вот часть программы, которая отправляет ArrayList с сервера на клиент. Я хочу удалить предупреждение о последней строке в этом коде:
Код клиента:
Socket s;
(...)
// A server is sending a list from the other side of the link.
ois = new ObjectInputStream(s.getInputStream());
MyList = (ArrayList<MyVariable>) ois.readObject();
MyVariable - это класс Java с некоторыми атрибутами. Сервер создает ArrayList и заполняет его переменными MyVariable в качестве элементов. Затем он отправляет полный список клиенту.
Я хотел бы знать, почему у меня есть предупреждение и как правильно кодировать, чтобы иметь 0 предупреждений. Если это возможно, я бы хотел избежать использования "@SuppressWarnings("unchecked")".;)
Спасибо,
Луис
4 ответа
Попробуй это
Object obj = ois.readObject();
// Check it's an ArrayList
if (obj instanceof ArrayList<?>) {
// Get the List.
ArrayList<?> al = (ArrayList<?>) obj;
if (al.size() > 0) {
// Iterate.
for (int i = 0; i < al.size(); i++) {
// Still not enough for a type.
Object o = al.get(i);
if (o instanceof MyVariable) {
// Here we go!
MyVariable v = (MyVariable) o;
// use v.
}
}
}
}
Невозможно избежать этого предупреждения. readObject()
возвращает объект. Вы должны разыграть это. И приведение к универсальному типу всегда будет генерировать такое предупреждение.
Если вы хотите сделать свой код как можно более чистым, что является хорошей идеей, вы должны соблюдать соглашения об именах Java, и имена переменных должны начинаться со строчной буквы.
Я столкнулся с проблемой, аналогичной OP, и нашел хорошее решение с помощью комбинации комментариев из @VGR и метода Java 1.8 для массивов.
Я предоставлю свой ответ с точки зрения вопроса ОП, поэтому он является общим и, надеюсь, поможет другим:
Вместо того, чтобы возвращать коллекцию (список), возвращайте массив с сервера. Преобразуйте коллекцию в массив, используя следующий код на стороне сервера:
myVariableList.toArray(new MyVariable[0]);
Если производительность является проблемой, описанной выше, можно использовать следующее, так что размер массива не нужно изменять:
myVariableList.toArray(myVariableList.size());
На стороне клиента преобразуйте массив объекта в массив класса MyVariable.
Это специфично для JAVA 8.
MyVariable[] myVarArr = Arrays.stream(ois.readObject()).toArray(MyVariable[]::new);
Затем, наконец, преобразовать массив в коллекцию (список).
List<MyVariable> myList = Arrays.asList(myVarArr);
Благодарю.
Мне это не нравится, но вы можете иметь контейнер (вроде псевдонима или typedef):
// add "implements Serializable" in your case
private static class MyVariableList {
public List<MyVariable> value;
}
И работать с MyVariableList
вместо. Таким образом, вы явно предоставляете компилятору достаточно информации для проверки типов во время выполнения.
Я тоже столкнулся с подобной ситуацией и смог ее решить. Мое решение, примененное к примеру ОП, таково:
myList = (ArrayList<Someclass>) Arrays.asList( (Someclass[]) ois.readObject() );
Я изменил соглашения об именах (как уже было предложено кем-то) на стандартную Java (объекты начинаются со строчных букв), и я переименовал класс MyVariable
в Someclass
чтобы было ясно, что это действительно относится к любому классу (а не только к переменным). Я также предполагаю, что соответствующий объект myList
на стороне сервера типа ArrayList<Someclass>
был записан в поток как массив Someclass[]
, Обратите внимание, что это легко сделать и аналогично первой части того, что уже предлагал абхишек, но мое решение отличается от последнего шага тем, что:
- Я избегаю звонить
Arrays.stream
- Его легче читать и быстро воспринимать как простое (без дальнейшей логики) и
checked
(не генерирует предупреждение).