我一直想知道java编译器/解释器如何设法提供字节码/源代码与文件输入和输出之间的交互。
我理解InputStream和OutputStream是所有文件i / o类的超类,但在阅读完它们之后,它们没有提供基本文件交互方法(read()和write(byte b))的实现。我最初的想法是,编译器可能会将这些方法转换为某些字节码操作(从文件返回一个字节或将一个字节写入文件),这些操作只发生在这个实例中,但这可能不正确。
如果将Java编译为程序集,那么我理解某个指令将被转换为特定于平台的文件i / o代码(例如cout<<< ... in C),但这显然是(afaik)不是Java的情况,因为它被编译为字节码。
任何人都可以启发我吗?
答案 0 :(得分:2)
与所有类一样,并且因为它们不是接口,所以会发生在方法上会有invokevirtual
,没有别的(JVM中有5个调用操作码:invokevirtual
, invokeinterface
,invokespecial
,invokestatic
和invokedynamic
)。
现在,当然,JRE肯定会有一些native
方法来处理操作系统级别的东西(例如在处理File*Stream
时);而对于它的重要性,实际的*Stream
实现可能因操作系统而异,也可能因JRE而异。重要的是,该方法符合其合同所述的方式。
之后,在运行时,JIT可以用更高效的代码(甚至本机代码)替换它。但InputStream
和OutputStream
类似于任何其他类;这些细节与Java开发人员无关,当然,这对JDK开发人员来说至关重要;)
答案 1 :(得分:2)
文件I / O由操作系统提供。在Linux上编写文件与在Windows上编写文件的工作方式不同。即使像C这样的低级语言通常在标准库中提供一个抽象层,使其看起来相同,但是生成的任一平台的二进制代码都会调用完全不同的操作系统函数。这意味着任何文件I / O最终都是特定于操作系统的任务。 Java中的OS抽象是由Java虚拟机提供的。
所有Java标准类(如java.io.FileOutputStream
)的实现都随特定于操作系统的Java虚拟机一起提供(当您点击"免费Java下载"在Java上获得的软件)。 COM)。 JVM可以用Java实现这些类的方法,也可以选择实现native
{{1}}的方法。
这意味着该方法是用编写JVM的编程语言实现的。当类执行必须通过调用操作系统(如文件IO)提供的内容时,它只能本机实现。 / p>
答案 2 :(得分:2)
InputStream
和OutputStream
类本身不提供任何实现。它们都是抽象类,需要派生类来提供实现。例如,read()
类is an abstract method的InputStream
方法:
public abstract int read() throws IOException
现在,派生类可以以它认为合适的任何方式提供实现,但是正确的是低级操作(例如需要访问系统调用的操作)最终需要一些无法在纯Java中实现的引导代码
例如,如果您查看source code for FileInputStream
,您会看到其read()
方法被声明为原生:
public
class FileInputStream extends InputStream
{
/* (...) */
public native int read() throws IOException;
/* (...) */
}
由于FileInputStream
是核心Java类,JVM可能会采用一些快捷方式,但实现本机方法的典型方法是Java Native Interface (JNI)。 JNI使得可以提供用不同语言(如C。
这一切如何融合在一起?当你编译一个使用read()
FileInputStream
方法的类时,就编译器而言,你只是使用某些类的某种方法,字节码将与任何类相同其他方法和类。在运行时,执行调用时,之前加载FileInputStream
类的JVM知道您调用的方法是本机方法,并调用其本机实现。