This is the difference between static and dynamic typing. Languages with
dynamic static typing - like
Java - allow the compiler to check for certain types of error. Like calling a method that doesn't exist on that object, or passing an object of one type as an argument when a method expects an object of another type.
The idea behind this is that errors that can be caught at compile time are usually much easier to diagnose and fix than errors that only happen at run time. Especially if the error is in code that doesn't get run every time, and especially if you don't have a complete set of automatic tests that will catch these errors.
In order to do this sort of static checking, you need to tell the compiler what the type of each variable is. There are some statically typed languages that try to infer the type from how the variable is used, but that isn't easy with a language with inheritance, and Java doesn't do that.