Я пишу небольшое Java-приложение, которое использует сериализацию/десериализацию для сохранения/загрузки ArrayLists. Я написал следующую функцию, которая принимает путь к файлу и десериализует объекты внутри него:
private Object deserialize(String fileName)
throws IOException, ClassNotFoundException {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName))) {
return ois.readObject();
}
}
Поскольку эта функция возвращает тип объекта, мне пришлось бы привести его к ArrayList следующим образом:
ArrayList<String> arrayList = (ArrayList<String>)deserialize("test.file");
(Строка выше должна быть окружена оператором try/catch, но я не включил его сюда для удобочитаемости)
Этот процесс отлично сработал для меня, однако я хотел попробовать и посмотреть, смогу ли я отредактировать код так, чтобы мне не пришлось самостоятельно приводить объект, и поэтому я в шутку набрал Любой в качестве возвращаемого типа моего функция, и компилятор не жаловался. Затем я изменил свою функцию на следующую, и, к моему удивлению, она действительно сработала!
private <Any> Any deserialize(String fileName)
throws IOException, ClassNotFoundException {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName))) {
return (Any)ois.readObject();
}
}
При использовании этой функции мне больше не нужно приводить возвращаемое значение к ArrayList, и вместо этого я могу просто использовать:
ArrayList<String> arrayList = deserialize("test.file");
Часть меня хочет просто смириться со всем этим и просто использовать функцию, не задаваясь вопросом, как она работает, но я знаю, что у меня будут проблемы с этим.
Может кто-нибудь объяснить, почему эта функция работает именно так, или перефразируя, просто объясните ключевое слово Любой, поскольку я, честно говоря, никогда раньше его не видел.
Но это всегда будет работать только в том случае, если предполагаемый тип на месте вызова — Object
. В противном случае вы можете получить ClassCastException
, если читаемый объект не относится к предполагаемому типу.
См. errorprone.info/bugpattern/TypeParameterUnusedInFormals для объяснения того, почему такое использование дженериков не такая уж хорошая идея.
Any
не является ключевым словом в Java. Главное, на что следует обратить внимание, — это <Any>
после модификатора доступа. Это общая спецификация метода — метод обобщается с помощью параметра типа с именем Any
(который вы затем используете для приведения в теле метода), и когда вы вызываете метод, Java будет сделать вывод о возвращаемом типе.
Но ничего особенного в слове «Любой» нет. Вы могли бы использовать «T», «SomeType» или даже «SpongeBob» для того же эффекта.
Плюс 1 для Губки Боба
А, это имеет смысл. Я знаком с дженериками, но у меня не было надлежащего мышления, чтобы понять, что «любой» был параметром, и вместо этого считал, что это ключевое слово. Я полагаю, это объясняет, почему я не смог найти никакой документации по ключевому слову «Любой», потому что его даже не существует!
Any
здесь просто переменная универсального типа, а не ключевое слово. Это ничем не отличается от того, если бы вы использовалиT
,V
,RESULT
или что-то еще. Другими словами, вы сделали метод универсальным и выполнили приведение в месте вызова скрытый.