abstract方法可以直接調用?

先看一段代碼:

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方法。


發佈了32 篇原創文章 · 獲贊 7 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章