bs is a Base reference, so, even if it references a Sub instance, you can only call methods defined (or declared) in Base through a Base reference. Method foo() in Sub is not overriding foo() in Base. If it had the same signature, it would work polymorphically, but here the signature is different. So, in Sub you have foo() as defined in Sub and the other one inherited from Base---both are available. But from a Base reference only the superclass version is available.
Everything Greg says is correct. I just wanted to add a reminder that it's up to the compiler to choose between overloaded methods, and that choice can only consider the declared type of the reference variable you're calling the method on -- i.e., the actual class of the object is not considered.