Потому что интерфейс определяет общее поведение для всех реализующих классов. Допустим, у вас есть некоторые другие классы, все реализующие X, вы ожидаете, что если у вас есть объект класса X, вы можете вызвать foo с параметром класса X (который может быть любым из его подклассов или реализаций), так что давайте скажем: иметь такой код:
class Z implements X {
...
}
Z z = new Z();
X x = new Y();
x.foo(z);
Что было бы ложным, поскольку с вашим кодом foo будет принимать только аргументы класса Y