Basically, the error is that when some system uses virtual function calls via an interface, what that's really saying is that: "This can be changed at runtime."
So if there's some function "void foo( IBar bar )", then what that's really saying is that "bar" can change at runtime. Literally a different implementation from call-to-call.
Is that actually required?
In 99.9% of such function calls, no: the implementation of IBar will always be the same concrete class.
To see a language that has gone to the opposite end of the spectrum, take a look at Rust. It use a lot of parametric typing, which is very flexible, but by default tends to use compile-time static types instead of run-time dynamic types.
Java never went down this path because it added parametric types very late in its design.
C# had parametric types in v2.0, which is when it started getting popular.
Rust had it from the beginning.