Java is designed to maximize portability. Many details about Java are specifically defined for all implementations. For example, an int is a 32-bit two's complement signed integer. Many languages leave precise definitions to particular implementations, making only general guarantees such as minimum range, or provide a way to ask the system what range is on the current platform.
Java makes these definitions all the way down to the machine language into which Java code is translated. Java source code is compiled into Java bytecodes , designed to be run on a Java virtual machine. Bytecodes are a machine language for an abstract machine, but are interpreted by the virtual machine on each system that supports Java.
The virtual machine assigns each application its own runtime, which both isolates applications from each other and provides a security model. Each runtime's security manager decides on the capabilities available to the application. The security manager could, for example, forbid the application from reading and writing the local disk, or allow network connections only to particular machines.
These features combined give Java code complete platform independence to provide a security model suitable for executing code downloaded across the network at varying levels of trust. Java source code compiled into bytecodes can be run on any machine with a Java virtual machine. The code can be executed with an appropriate level of protection to prevent careless or malicious class writers from harming the system. the level of trust can be adjusted depending on the source of the bytecodes - bytecodes on the local disk or protected network can be trusted more than bytecodes fetched from arbitrary machines elsewhere in the world.
See Java in a Nutshell pages7 and 142 about bytecodes and security.
Also see Exploring Java about code verification,
The verifier is a type of theorem prover. It steps through the Java bytecode and applies simple, inductive rules to determine certain aspects of how the bytecode will behave. This kind of analysis is possible because compiled Java bytecode has a lot more type information stored within it than other languages of its kind. The bytecode also has to obey a few extra rules that simplify its behavior. First, most bytecode instructions operate only on individual data types. For example, with stack operations, there are separate instructions for object references and for each of the numeric types in Java. Similarly, there is a different instruction for moving each type of value into and out of a local variable.
Second, the type of object resulting from any operation is always known in advance. There are no bytecode operations that consume values and produce more than one possible type of value as output. ..."(pages 15-17)
The Byte Code Verification Process from the Java White Paper