java源代码最终如何与文件交互?
我一直在想java编译器/解释器是如何提供字节码/源代码与文件输入和输出之间的交互的 我知道InputStream和OutputStream是所有文件I/o类的超类,但在阅读它们之后,它们没有提供基本文件交互方法(read()和write(byte b))的实现。我最初的想法是,编译器可能会将这些方法转换为某些字节码操作(从文件返回一个字节或将一个字节写入文件),这些操作只在这个实例中发生,但这可能不正确java源代码最终如何与文件交互?,java,file-io,bytecode,Java,File Io,Bytecode,我一直在想java编译器/解释器是如何提供字节码/源代码与文件输入和输出之间的交互的 我知道InputStream和OutputStream是所有文件I/o类的超类,但在阅读它们之后,它们没有提供基本文件交互方法(read()和write(byte b))的实现。我最初的想法是,编译器可能会将这些方法转换为某些字节码操作(从文件返回一个字节或将一个字节写入文件),这些操作只在这个实例中发生,但这可能不正确 如果Java被编译成汇编语言,那么我知道某条指令会被转换成特定于平台的文件I/o代码(例如
如果Java被编译成汇编语言,那么我知道某条指令会被转换成特定于平台的文件I/o代码(例如,cout,就像所有类一样,因为它们不是接口,所以会发生的事情是在方法上会有一个
invokevirtual
,而不是别的(JVM中有5个调用操作码:invokevirtual
,invokeinterface
,invokespecial
,invokestatic
和invokedynamic
)
现在,当然,JRE肯定会有一些本地
方法来处理操作系统级的东西(例如在处理File*Stream
s时);重要的是,实际的*Stream
实现可能因操作系统而异,也可能因JRE而异。重要的是,该方法按照其合同中的规定执行
之后,在运行时,JIT可能会用更高效的代码(甚至是本机代码)替换它。但是
InputStream
和OutputStream
与其他类一样;这些细节与Java开发人员无关,但对JDK开发人员来说当然是最重要的;)文件I/O由操作系统提供。在Linux上编写文件的工作方式与在Windows上编写文件的工作方式不同。即使是像C这样的低级语言,通常也会在标准库中提供一个抽象层,使其外观相同,但为这两种平台生成的二进制代码调用完全不同的操作系统功能这意味着任何文件I/O最终都是操作系统特定的任务。Java虚拟机提供了Java中的OS抽象
所有Java标准类(如Java.io.FileOutputStream
)的实现都随操作系统特定的Java虚拟机(单击Java.com上的“免费Java下载”即可获得的软件)一起提供JVM可以在Java中实现这些类的方法,或者可以选择实现一个方法native
,该方法
这意味着该方法是用编写JVM的编程语言实现的,只能本机实现。InputStream和
OutputStream
类本身不提供任何实现。它们都是抽象类,需要派生类来提供实现。例如,InputStream
类的read()
方法:
现在,派生类可以以它认为合适的任何方式提供实现,但是您可以正确地看到,底层操作(例如需要访问系统调用的操作)最终需要一些引导代码,而这些代码不能单独在纯Java中实现
例如,如果查看,您将看到其read()
方法声明为本机:
public
class FileInputStream extends InputStream
{
/* (...) */
public native int read() throws IOException;
/* (...) */
}
由于FileInputStream
是一个核心Java类,JVM可能会采取一些快捷方式,但实现本机方法的典型方式是通过。JNI使提供用不同语言(如C)编写的Java方法的实现成为可能
这一切是如何结合在一起的?当您编译一个使用
read()的类时
FileInputStream的方法,就编译器而言,您只是在使用某个类的某个方法,字节码将与任何其他方法和类的字节码相同。在运行时,当您执行调用时,先前加载了FileInputStream
类的JVM知道您正在调用的方法是一个本机方法,并调用其本机实现。内存(字节数组)的write(int)
的常见实现是什么流、文件输出流或网络流?某些操作有本机
代码,因此并非所有操作都由JVM处理。最终,I/O确实涉及与JVM运行的操作系统交互的特定于平台的本机代码。顺便说一句:对于NIO(.2)()类InputStream
和OutputStream
类不是所有文件I/O的超类(但这些实现也可能包含特定于平台的native
实现)
public
class FileInputStream extends InputStream
{
/* (...) */
public native int read() throws IOException;
/* (...) */
}