Reputation: 5647
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?
Upvotes: 2
Views: 624
Reputation: 1063
The InputStream
and 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:
public
class FileInputStream extends InputStream
{
/* (...) */
public native int read() throws IOException;
/* (...) */
}
Since 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.
Upvotes: 2
Reputation: 69663
File I/O is provided by the operating system. Writing a file on Linux works differently than writing a file on Windows. Even low-level languages like C usually provide an abstraction layer in the standard library to make it look the same, but the generated binary code for either platform calls completely different operating system functions. That means any file I/O is in the end an operating-system specific task. OS abstraction in Java is provided by the Java Virtual Machine.
The implementation of all Java standard classes (like java.io.FileOutputStream
) is shipped with your OS-specific Java Virtual Machine (the software you get when you click on "Free Java Download" on java.com). The JVM can implement the methods of these classes in Java, or can choose to implement a method native
which looks like this.
This means that the method is implemented in the programming language the JVM is written in. When the class does something which must be provided by a call to the operating system (like file IO), it can only be implemented natively.
Upvotes: 2
Reputation: 121710
Like all classes, and since they are not interfaces, what will happen is that there will be an invokevirtual
on the method, nothing else (there are 5 invocation opcodes in the JVM: invokevirtual
, invokeinterface
, invokespecial
, invokestatic
and invokedynamic
).
Now, of course, the JRE will certainly have some native
methods to deal with OS-level stuff (when dealing with File*Stream
s for instance); and for what it matters, the actual *Stream
implementations may differ from OS to OS, and from JRE to JRE as well. All that matters is that the method does what its contract says it does.
After that, at runtime, the JIT may replace it with more efficient code (even native code). But InputStream
and OutputStream
are classes like any other; such details are of no relevance to the Java developer but, of course, of the utmost importance to the JDK developer ;)
Upvotes: 2