Чем отличаются ссылка или тип слева от равно от того что справа (при инициализации экземпляра объекта)?
Допустим дан простейший пример:
Cat b = new Dog();
b - Это экземпляр того что слева, класса кат или дог?
А Вот посложнее:
Collection d = new ArrayList<>();
d - это экземпляр класса ArrayList, а причём тогда Collection? И чем тогда будет отличаться от:
ArrayList d = new ArrayList<>();
Если слева это просто ссылка типа ArrayList (как мы делаем к примеру Cat cat, где cat ссылка на класс Cat), то какой смысл вообще ставить слева (слово ArrayList) если то что справа главнее? )
Так ведь тип, который справа переходит экземпляру типа того что слева, так получается.
Ответы (2 шт):
Cat b = new Dog();
Не скомпилируется, если Dog не наследуется от Cat. Если же наследуется, то в программе явно нестандартная теория эволюции используется.
В переменной всегда окажется то, что вы в неё запишите, т.е. то, что идёт справа от =.
Указывают же супер-тип или интерфейс для удобства обычно. Также это общепринятое соглашение - указывать минимально подходящий тип при объявлении переменной. Делается это по нескольким причинам:
- Чтобы случайно не получить доступ к ненужным методам класса. Если у переменной вы будете вызывать только методы супер-класса, то вам не нужно иметь доступ к методам класса-наследника.
- Возможно, вам захочется потом в переменную положить другого наследника супер-класса. Если вы не укажите их общий тип при объявлении переменной - у вас это не получится - компилятор будет ругаться.
Рассмотрим ваш пример с Collection:
Collection col = new ArrayList<>();
ArrayList arr = new ArrayList<>();
Действительно, переменная col объявлена как Collection, но указывает на ArrayList. Это означает, что вы можете на этой переменной вызывать только те методы, которые есть у Collection, игнорируя специфику ArrayList.
Конкретно, вы не можете выполнить метод col.sort(...), хотя реально у вас ArrayList, который этот метод поддерживает. А вот arr.sort(...) -- пожалуйста.
Итак, то, что слева, -- это тип переменной, он определяет, какие методы можно вызывать на этой переменной и что чему можно присваивать (при передаче параметров, например). То, что справа, -- это реальные объекты в хипе.
Ситуация, когда что-то общее ссылается на что-то более специфичное -- нормальна. Например, у вас есть метод, который принимает в качестве параметра коллекции. Любые коллекции. Например, так:
public static void printCollection(Collection col) {
for (Object o : col) {
System.out.println(o);
}
}
Посмотрите, как интересно, мы можем передать ему хоть ArrayList, хоть LinkedList, хоть HashSet, хоть (не приведи господи) PriorityQueue. И он нормально отработает.
Вот какая ему разница, какую коллекцию ему передали?! Главное, что это Collection, а значит там есть метод Iterator<T> iterator(); (а у всех подтипов Collection он есть). А значит параметр можно пролистать в цикле for.
Собственно для этого все эти штуки и придуманы.