Страницы

Поиск по вопросам

четверг, 1 ноября 2018 г.

Для чего приведение к типу в методе findViewById()

Изучаю ANDROID, вот пример листинга:
Button newMyBtn = (Button) findViewById(R.id.myBtn);
Синтаксически запись правильна, только я вот одного понять не могу, зачем здесь вот это самое приведения объектной ссылки? Что, нельзя в объект newMyBtn сразу положить вызов метода findViewById?
Я почитал Хорстаманна и нашел (но все равно остался непонятен принцип данного приведения):
Чтобы выполнить приведение объектной ссылки, используются такие же синтаксические конструкции, как и для числовых выражений. Имя требуемого класса надо поместить в скобки и поставить перед объектной ссылкой, которую нужно преобразовать. Пример соответствующего выражения приведен ниже.
Manager boss = (Manager) staff[0]; Для приведения типов существует только одна причина — необходимость использовать все возможности объекта после того, как его фактический тип был на время забыт. Например, в классе ManagerTest массив staff представляет собой массив объектов Employee. Этот тип выбран, поскольку некоторые элементы массива хранят информацию об обычных сотрудниках. Чтобы получить доступ ко всем новым полям класса Manager, нам может понадобиться привести тип некоторых элементов массива к типу Manager. (В примере, рассмотренном выше, мы предприняли специальные меры, чтобы избежать приведения типов. Мы инициализировали переменную boss объектом Manager, перед тем как поместить ее в массив. Для того чтобы задать размер премии, нужно знать правильный тип объекта.)


Ответ

Проблема в различии двух вещей: декларируемого и фактического типа объекта.
Дело в том, что метод findViewById не может знать, что по данному id будет лежать именно Button. Поэтому он декларирует тип возвращаемого объекта как View — это максимальная гарантия, которую он может дать. Фактически возвращённый объект может быть любого производного от View типа.
Итак, у нас findViewById возвращает View, который, как мы уверены, фактически будет Button'ом. Для того, чтобы работать с ним как с Button'ом, мы должны иметь ссылку типа Button. Мы её декларируем: Button newMyBtn
Теперь, у нас инициализация ссылки типа Button другой ссылкой, у которой декларируемый тип — всего лишь View. Система не уверена в том, что фактическим типом будет Button. Для того, чтобы убедить её в этом, мы используем приведение к нужному типу (Button)findViewById(...)
Эта конструкция фактически означает: «Я уверен, что фактический тип объекта будет Button или производный от него. Причём настолько уверен, что согласен крешнуть программу, если это не так.» (Точнее, выбросить исключение, да.) При этом компилятор соглашается с вашими доводами, и приводит декларируемый тип View к Button. (Если во время выполнения там реально будет не Button, вы таки получите исключение.)
Без приведения вы не убедите компилятор, что тип у ссылки правильный.
Почему для компилятора важно убедиться в правильности типа? Потому что если у вас ссылка newMyBtn имеет заявленный тип Button, то вы можете у неё вызывать методы, специфичные для Button'а, и обращаться к полям, которые есть в Button'е. Если этот объект окажется фактически другого типа, и таких полей в нём не будет, что тогда? Компилятор заботится о том, чтобы таких ситуаций не возникало. (Это называется словом «типобезопасность».)

Комментариев нет:

Отправить комментарий