先看一段代码:
import java.io.IOException;
public class RuntimeTest {
public static void main(String[] args) throws IOException, InterruptedException{
Process p=Runtime.getRuntime().exec("notepad.exe");
p.waitFor();
System.out.println("end!");
}
查看文档,发现Process类的waitFor()方法是一个abstract方法。可是为什么可以直接调用啊???
恩,直觉上想,应该是下面这行代码,实际返回的是Process类的一个子类,在子类中重写了waitFor()方法。
Runtime.getRuntime().exec("notepad.exe");
那实际情况呢?我们查看下源码JDK1.5:
Runtime的源码,重载了好几个exec方法,但所有的exec方法都是调用下面这个方法来实现的。
public Process exec(String[] cmdarray, String[] envp, File dir)
throws IOException {
return new ProcessBuilder(cmdarray)
.environment(envp)
.directory(dir)
.start();
}
那我们再来查看ProcessBuilder的start方法源码:
public Process start() throws IOException {
// Must convert to array first -- a malicious user-supplied
// list might try to circumvent the security check.
String[] cmdarray = command.toArray(new String[command.size()]);
cmdarray = cmdarray.clone();
for (String arg : cmdarray)
if (arg == null)
throw new NullPointerException();
// Throws IndexOutOfBoundsException if command is empty
String prog = cmdarray[0];
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkExec(prog);
}
String dir = directory == null ? null : directory.toString();
try {
return ProcessImpl.start(cmdarray,
environment,
dir,
redirects,
redirectErrorStream);
} catch (IOException | IllegalArgumentException e) {
String exceptionInfo = ": " + e.getMessage();
Throwable cause = e;
if ((e instanceof IOException) && security != null) {
// Can not disclose the fail reason for read-protected files.
try {
security.checkRead(prog);
} catch (AccessControlException ace) {
exceptionInfo = "";
cause = ace;
}
}
// It's much easier for us to create a high-quality error
// message than the low-level C code which found the problem.
throw new IOException(
"Cannot run program \"" + prog + "\""
+ (dir == null ? "" : " (in directory \"" + dir + "\")")
+ exceptionInfo,
cause);
}
}
可以看到,返回的是:ProcessImpl.start(cmdarray,environment,dir, redirects, redirectErrorStream);,那就再查看ProcessImpl类的源码。
package java.lang;
import java.io.IOException;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileDescriptor;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.lang.ProcessBuilder.Redirect;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/* This class is for the exclusive use of ProcessBuilder.start() to
* create new processes.
*
* @author Martin Buchholz
* @since 1.5
*/
final class ProcessImpl extends Process {
<pre name="code" class="java">/*
*中间部分代码省略
*/
// System-dependent portion of ProcessBuilder.start() static Process start(String cmdarray[], java.util.Map<String,String> environment, String dir, ProcessBuilder.Redirect[] redirects, boolean redirectErrorStream) throws IOException { String envblock = ProcessEnvironment.toEnvironmentBlock(environment); FileInputStream f0 = null; FileOutputStream f1 = null; FileOutputStream f2 = null; try { long[] stdHandles; if (redirects == null) { stdHandles = new long[] { -1L, -1L, -1L }; } else { stdHandles = new long[3]; if (redirects[0] == Redirect.PIPE) stdHandles[0] = -1L; else if (redirects[0] == Redirect.INHERIT) stdHandles[0] = fdAccess.getHandle(FileDescriptor.in); else { f0 = new FileInputStream(redirects[0].file()); stdHandles[0] = fdAccess.getHandle(f0.getFD()); } if (redirects[1] == Redirect.PIPE) stdHandles[1] = -1L; else if (redirects[1] == Redirect.INHERIT) stdHandles[1] = fdAccess.getHandle(FileDescriptor.out); else { f1 = newFileOutputStream(redirects[1].file(), redirects[1].append()); stdHandles[1] = fdAccess.getHandle(f1.getFD()); } if (redirects[2] == Redirect.PIPE) stdHandles[2] = -1L; else if (redirects[2] == Redirect.INHERIT) stdHandles[2] = fdAccess.getHandle(FileDescriptor.err); else { f2 = newFileOutputStream(redirects[2].file(), redirects[2].append()); stdHandles[2] = fdAccess.getHandle(f2.getFD()); } } return new ProcessImpl(cmdarray, envblock, dir, stdHandles, redirectErrorStream); } finally { // In theory, close() can throw IOException // (although it is rather unlikely to happen here) try { if (f0 != null) f0.close(); } finally { try { if (f1 != null) f1.close(); } finally { if (f2 != null) f2.close(); } } }
/*
*中间部分代码省略
*/
public int waitFor() throws InterruptedException { waitForInterruptibly(handle); if (Thread.interrupted()) throw new InterruptedException(); return exitValue(); } private static native void waitForInterruptibly(long handle);} 可以看出,ProcessImpl类是Process类的一个子类,start方法最后返回了一个ProcessImpl对象。而且ProcessImpl重写了waitFor方法。