В этой статье мы познакомимся со статической типизацией и узнаем ее отличия от динамической типизации. Также рассмотрим пример статической типизации в Java. Сразу следует отметить, что в разных источниках слово «типизация» часто заменяется на «проверка типов программы» или на «проверка безопасности типов программы».
Статическая типизация — проверка безопасности типов программы на этапе компиляции (путем анализа исходного кода программы).
Динамическая типизация — проверка безопасности типов программы во время ее выполнения.
Java использует статическую проверку типов, то есть анализ программы во время ее компиляции. Основная идея выбора такого подхода проверки типов состоит в том, чтобы проверять типы только 1 раз при компиляции, тем самым повышая скорость выполнения программы. Также это позволяет обнаруживать возможные ошибки.
Статическая типизация в Java
Давайте рассмотрим простой пример статической типизации в Java. Есть два класса: Alpha и Beta с методами, которые что-то делают:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Alfa { Alfa getThis() { return this; } public void doAlfa() { System.out.println("что-то делаем в Alfa"); } } class Beta extends Alfa { public void doBeta() { System.out.println("что-то делаем в Beta"); } } |
Взгляните еще раз на код выше и скажите, что вернет метод new Beta().getThis()
? Это будет объект Alfa или все же Beta? Нам известно, что getThis()
объявлен в классе Alfa и во время компиляции компилятор видит, что метод возвращает объект Alfa. Но в нашем случае Beta наследует Alfa и вызов метода getThis()
{return this; (верни себя)} все же вернет объект Beta.
Мы описали классы для работы, а теперь рассмотрим как это работает:
Следующую строку нельзя будет вызвать, даже если мы думаем, что работаем с объектом Beta:
1 |
new Beta().getThis().doBeta(); |
Проблема заключается в том, что ее исходный тип Аlfa и компилятор не знает реальный тип во время компиляции, поэтому он видит объект типа Аlfa. Исходя из этого нам доступны такие операции:
1 |
new Beta().getThis().doAlfa(); |
или обойдем проблему с помощью приведения типов к Beta:
1 |
((Beta) new Beta().getThis()).doBeta(); |
Теперь попробуем добавить еще один класс:
1 2 3 4 5 |
class Omega extends Alfa{ public void doOmega() { System.out.println("что-то делаем с Omega"); } } |
И напишем такую строчку кода:
1 |
((Omega) new Beta().getThis()).doOmega(); |
Так написать можно и это даже пройдет статическую проверку типов (по той же причине, что и с new Beta().getThis().doBeta();
), однако во время выполнения будет брошено исключение «java.lang.ClassCastException: Beta cannot be cast to Omega
«, так как Beta не может быть приведена к Omega.