Selection by the receiver
A variable declared with a parent type can hold a child object, and a call to an overridden instance method can reach the child implementation. Java’s Animal/Cat example demonstrates this receiver-dependent choice.
Hiding a same-named static method follows different rules. Method names alone therefore do not determine whether a particular call uses dynamic dispatch.
Java also separates overload resolution from dynamic lookup. Given visit(Object) and visit(String), an argument statically typed Object does not make an ordinary invocation switch to the String overload at run time merely because it currently holds a String. Compilation first selects a method signature; applicable run-time lookup then finds the receiver’s implementation for that signature. This is Java’s division of responsibilities, not a universal limit on how all languages dispatch.
Interface pointers and method tables
Rust trait objects expose a common trait interface for different concrete types. Their pointers include a data pointer and virtual-method-table information whose function pointers identify concrete implementations.
A collection can consequently contain heterogeneous objects implementing the required interface. Callers depend on the permitted operations while each implementation retains its concrete representation.
Flexibility and static alternatives
Rust generics can instead be monomorphized into concrete implementations with statically known targets. Dynamic dispatch trades runtime flexibility for indirect selection and potentially fewer inlining opportunities.
These are implementation trade-offs, not proof that every dynamic call is slow or every generic language uses one strategy. A callable interface also does not by itself establish correct behavioral contracts.