I have been wondering about how the java compiler/interpreter manages to provide an interaction between bytecode/source code and file input and output.
I understand that InputStream and OutputStream are the super-classes of all file i/o classes, but after reading through them, they provide no implementation for the basic file interaction methods (read() and write(byte b)). My initial idea was that perhaps the compiler would translate these methods into certain bytecode operations (that return a byte from a file or write a byte to a file) that only occur in this instance, but this may not be correct.
If Java were compiled to assembly, then I understand that a certain instruction would be translated into platform-specific file i/o code (e.g. cout << ... in C), but this is obviously (afaik) not the case with Java since it's compiled to bytecode.
Can anyone enlighten me?
Best How To :
OutputStream classes do not provide any implementation themselves. They both are abstract classes that require derived classes to provide an implementation. For example, the
read() method of the
InputStream class is an abstract method:
public abstract int read() throws IOException
Now, a derived class can provide an implementation in any way it sees fit, but you are correct that low-level operations such as operations which require access to system calls ultimately need some bootstrapping code which cannot be implemented in pure Java alone.
For example, if you have a look at the source code for
FileInputStream, you will see its
read() method is declared native:
class FileInputStream extends InputStream
/* (...) */
public native int read() throws IOException;
/* (...) */
FileInputStream is a core Java class, the JVM may be taking some shortcuts, but the typical way to implement native methods is through the Java Native Interface (JNI). The JNI makes it possible to provide an implementation of a Java method written in a different language such as C.
How does this all fit together? When you are compiling a class which uses the
read() method of
FileInputStream, as far as the compiler is concerned, you are just using some method of some class, and the bytecode will be the same as for any other method and class. At runtime, when your call is executed, the JVM, having previously loaded the
FileInputStream class, knows the method you are calling is a native method, and calls its native implementation.