It provides extensive compile time checking, followed by a second level of runtime checking to ensure code has not been modified after compile.
Java interpreter lays out memory so that crackers/hackers (bad guys) can't make an assumption about how the memory is structured to insert their own virus.
Loaded classes cannot simply access the file system randomly. The compiler and run-time environment has protections against that access, unless programmed initially.
The memory management model has no pointers or pointer arithmetic which eliminates entire classes of programming errors that plague C and C++ programmers
Java is designed to operate in distributed environments, which means that security is of paramount importance. Java lets you construct applications that can't be invaded from outside (like viruses)