size всего лишь возвращает, сколько ключей реально лежит в папке.
Все твои рассуждения про "завели бакет", "кладем в новый бакет" неверны. Ты ничего не заводишь, это детали реализации хеш-таблицы. Бакет это связный список, в котором лежат пары ключ-значение, у которых хеш ключа равен по модулю количества бакетов. Это и есть тот список, который ты мечтаешь получить, и это так не работает. То есть ты его не получишь, тк это детали реализации.
И далее, ты эту реализацию сломал своими мутабельными ключами. В списке теперь лежит ключ, у которого хеш не соответствует списку. Естественно, мапа не найдет по этому ключу ничего, тк будет искать в другом списке(бакете). Вывод - никогда не мутируй ключи.
//заводим бакет который который будет всегда первым
map.put(null, null);
//значение перетерлось так как hashCode одинаков и equals вернул true
map.put(null, "afterNull");
Нет, всё не так. Нулл обрабатывается просто отдельно, под него отдельный элемент, это не бакет.
Когда ты ложить в мапу по одинаковому ключу разные значения, более позднее перетирает старое. Просто потому что в этом суть хеш-таблицы, и поэтому она так реализована. Бакеты не хранят одинаковые по хешу ключи, они хранят ключи с хешами, одинаковыми по модулю количества бакетов.
Сколько в данный момент в мапе бакетов тебя вообще заботить не должно.
Читай код. Видно, что ты где-то нахватался неправильно (или плохо) разжеванной теории, и пытаешься на этом выехать. Большинство твоих вопросов снимут сорсы хешмапы и, в крайнем случае, дебаггер.