先看一段代码:

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

abstract方法可以直接调用?相关推荐

  1. Virtual方法和Abstract方法的使用区别

    一.Virtual方法(虚方法) virtual 关键字用于在基类中修饰方法.virtual的使用会有两种情况: 情况1:在基类中定义了virtual方法,但在派生类中没有重写该虚方法.那么在对派生类 ...

  2. java 子类的同名方法_java 父类子类有同名方法时如何调用的实现

    父类引用默认调用子类重写的方法 如果父类的引用p指向了子类的实例,则通过这个引用p访问同名方法时,调用的是子类重写的方法. 父类引用p可以指向不同的子类,调用不同子类重写的不同的同名方法,进而达到类间 ...

  3. 温故而知新:new与override的差异以及virtual方法与abstract方法的区别

    先直接看代码吧: using System;namespace ConsoleApplication1 {class Program{static void Main(string[] args){B ...

  4. 零基础入门 自学 JAVA SE 基础篇(九)instanceof final 开闭原则 多态 抽象(abstract)方法与抽象类 接口(interface)

    JAVA SE自学 基础篇 多态 instanceof final 开闭原则 多态 抽象(abstract)方法与抽象类 接口(interface) 目标 父类型与子类型之间的转换及instanceo ...

  5. Java学习之路3——方法定义、调用【重拾Java】

    Java学习之路3--方法定义.调用[重拾Java] 方法定义 为什么要写方法 方法完整的定义形式.调用 方法定义的格式 修饰符 返回值类型 返回值 调用格式 方法重载 方法定义 为什么要写方法 对于 ...

  6. virtual方法和abstract方法的使用(轉載)

    在C#的学习中,容易混淆virtual方法和abstract方法的使用,现在来讨论一下二者的区别.二者都牵涉到在派生类中与override的配合使用.一.Virtual方法(虚方法)virtual 关 ...

  7. java 父类子类有同名方法时如何调用

    父类引用默认调用子类重写的方法 如果父类的引用p指向了子类的实例,则通过这个引用p访问同名方法时,调用的是子类重写的方法. 父类引用p可以指向不同的子类,调用不同子类重写的不同的同名方法,进而达到类间 ...

  8. abstract 类和 abstract 方法 (抽象类与抽象方法)

    抽象一直以来都是人们所神往的艺术形式,这点从梵高,毕加索等艺术家的身上就可以看出.抽象所代表的是一种形式上的美感,颇有一种虚无缥缈只可意会不可言传的意味.但是JAVA中的抽象类与抽象方法相对而言就更加 ...

  9. 笔记 16 abstract类和abstract方法

    abstract 类 用关键字abstract修饰的类称为abstract类(抽象类). abstract class A{ ........ } 用关键字abstract修饰的方法称为abstrac ...

最新文章

  1. 用python画爱心的代码-Python一行代码画个爱心案例
  2. 【深度好文】多线程之WaitHandle--派生EventWaitHandle事件构造-》AutoResetEvent、ManualResetEvent...
  3. 最接近的三数之和Python解法
  4. 埋点是什么意思_(一百二十二)埋点方案举例,如何做埋点方案
  5. mysql cluster安装配置_mysqlcluster安装与配置_MySQL
  6. 忍者X2简介+安装包+安装环境说明 [复制链接]
  7. 连接mysql的各种方式
  8. java 异步编程 CompletableFuture
  9. 机关事业单位考勤统计和活动抽奖小程序
  10. 容器化运行wine模拟器制作开源代码索引chm文件
  11. rest-assured一些使用心得
  12. arduino nano关于microUSB无法用的处理
  13. 飞塔防火墙密码忘记重置方法
  14. 删除按升序排列的单链表中的重复元素
  15. 邮件退回 对方服务器不允许,主 题:我给别人发的邮件被退回来了如何处理?...
  16. MATLAB处理EXCEL文件
  17. 小半斤拔凉 支付Java 相关参考
  18. 【智能制造】智能生产:智能制造的主线
  19. 架构设计文档提纲简描
  20. 后台管理系统2——文件上传功能、富文本编辑器集成

热门文章

  1. 【太阳线】级差+平级奖+加权分红源码系统 演示网站介绍
  2. 基于B/S模式的学校教材信息管理系统设计
  3. FBX导入虚幻5_详解
  4. unity入门——实现一个简单的跑酷游戏(人物控制)
  5. What is a service mesh? And why do I need one?
  6. Vue响应式原理Vue中数据的监听
  7. 解决windows下安装cnpm后,cnmp不是内部命令的问题
  8. TDSQL助力建设数字政务
  9. 外观和样式(04):【参】颜色空间
  10. php 转换 json 方法