Посмотрите на две части инструкции:
Base b2
, которая объявляет переменную с именем b2
типа Base
.Вы можете назначить ссылку на эту переменную, если ссылка имеет значение null или ссылается на экземпляр Base
или подкласс Base
.
Тогда
new Child()
создает новый экземплярChild
.Child
является подклассом Base
, поэтому вы можете присвоить ссылку, возвращаемую конструктором, переменной b2
.
Теперь вы можете «видеть» только элементы с Base
по b2
, хотя фактическое значение относится к экземпляру Child
во время выполнения.Но любые методы из Base
, которые были переопределены в Child
, будут использовать переопределенную версию при вызове ... поэтому, когда вы вызываете
b2.subtract();
, JVM находитиз фактического типа объекта, на который ссылается b2
, и использует реализацию этого класса subtract
- в этом случае метод, который печатает «Child Subtract».
EDIT: Вы специально спросили, где вы можете использовать такие вещи и как это помогает ...
Вы можете использовать его в любое время, когда захотите объявить переменную более общего типа (суперкласс илиинтерфейс), но присвойте ему значение, которое является подклассом или реализацией интерфейса.В качестве другого примера:
List<String> strings = new ArrayList<String>();
Основным преимуществом объявления переменной обычным способом является то, что вы сохраняете гибкость - позже вы можете перейти от использования ArrayList<T>
к другой реализации List<T>
и код все еще должен работать.Вы в основном говорите: «Мне нужны только члены и гарантии, предоставляемые List<T>
- тот факт, что я использую ArrayList<T>
, несколько случайен».
Подобный пример - решение, какой тип методадолжен возвращаться - часто вы хотите объявить, что вы возвращаете общий тип (или интерфейс), даже если реализация знает, какой конкретный тип он возвращает.Это скрывает детали реализации, что позволяет изменить их позже.