В вашем примере новый объект создается на каждой итерации цикла. Список может различать их, потому что он не заботится о том, чтобы вы называли их все «a» в вашем коде, он отслеживает их по ссылке, которая переназначается при каждом вызове
a = new A();
Каждый раз, когда вызывается эта строка кода, в куче создается новый объект, и его адрес в памяти присваивается ссылке a. Это та ссылка, в которой хранится список, а не имя переменной.
Это идеальный и нормальный способ заполнения списка (кроме синтаксических ошибок, упомянутых другими, которые, я полагаю, вы можете исправить, когда пытаетесь скомпилировать код).