乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 Java概述与环境搭建

    • Java概述与环境搭建
    • Java语言概述
    • 解释型语言与编译型语言对比
    • JDK安装与配置
    • JDK、JRE、JVM 详解
    • HelloWorld程序详解
    • IDE 介绍
  • 第2章 标识符与基本数据类型

    • 章节导读
    • 变量概述
    • 常量概述
    • 基本类型与包装类
    • 字节型 byte
    • 短整型 short
    • 整型 int
    • 长整型 long
    • 单精度浮点型 float
    • 双精度浮点型 double
    • 字符型 char
    • 布尔型 boolean
    • 类型转换
  • 第3章 运算符与表达式

    • 章节导读
    • 算术运算符
    • 赋值运算符
    • 关系运算符
    • 逻辑运算符
    • 位运算符
    • 条件运算符
    • 运算符优先级
    • 表达式
  • 第4章 流程控制

    • 章节导读
    • 常见的程序运行流程
    • if-else 选择结构
    • switch 多分支选择
    • while 循环
    • do-while 循环
    • for 循环
    • break 与 continue
  • 第5章 数组

    • 章节导读
    • 一维数组
    • 多维数组
    • Arrays 工具类
  • 第6章 类与对象

    • 章节导读
    • 类与对象
    • 方法定义与调用
    • 构造方法
    • 封装
    • 访问修饰符
    • package 与 import
    • static 关键字
    • this 关键字
    • 参数传递 详解
    • 枚举
    • 成员内部类
    • 局部内部类
    • 静态内部类
    • 匿名内部类
  • 第7章 接口与继承

    • 章节导读
    • 继承
    • super 关键字
    • final 关键字
    • 多态
    • 向上转型与向下转型
    • 抽象类
    • 接口
    • 抽象类与接口对比
  • 第8章 注解

    • 章节导读
    • 注解基础
    • 元注解详解
    • 自定义注解
  • 第9章 常用类

    • 章节导读:Java 常用类
    • Object 类:万类之祖
    • 包装类:基本类型的对象化
    • String:不可变的字符串
    • StringBuffer:线程安全的可变字符串
    • StringBuilder:可变的字符串构建器
    • Math:数学运算工具类
    • Random:伪随机数生成器
    • 大数值运算 详解
    • 日期时间API 详解
  • 第10章 异常机制

    • 章节导读
    • 异常体系与分类
    • try-catch-finally
    • try-with-resources
    • throws 与 throw
    • 自定义异常
  • 第11章 泛型

    • 章节导读
    • 泛型基础
    • 通配符与PECS原则
    • 类型擦除
  • 第12章 集合框架

    • 章节导读
    • 集合框架概述
    • ArrayList
    • LinkedList
    • HashMap 详解
    • LinkedHashMap 详解
    • TreeMap 详解
    • HashSet
    • TreeSet 详解
    • TreeSet 与 Comparable
    • Collections 工具类详解
  • 第13章 IO流

    • 章节导读
    • IO流概述
    • 字节流
    • 字符流
    • 缓冲流
    • 转换流 详解
    • 序列化 详解
    • NIO与Files 详解
    • NIO与Files工具类
  • 第14章 多线程与并发

    • 第十六章 多线程与并发 —— 章节导读
    • 线程基础详解
    • synchronized 详解
    • Lock 与显式锁详解
    • volatile 详解
    • wait 与 notify 详解
    • ThreadLocal详解
    • 原子类详解
    • 并发工具类详解
    • 线程池详解
  • 第15章 反射

    • 章节导读
    • 反射概述与 Class 对象
    • Constructor 与对象创建
    • Field与Method详解
    • 反射应用详解
  • 第16章 JDK8新特性

    • 章节导读
    • Lambda 表达式
    • Stream API 基础
    • Stream API 高级详解
    • Optional 详解
    • 新日期时间API详解
  • 第17章 JDK9-11新特性

    • 章节导读
    • 模块化系统 — Project Jigsaw(JDK 9)
    • var 局部变量类型推断(JDK 10)
    • 集合工厂方法与增强(JDK 9 / 10 / 11)
    • 接口增强:private 方法(JDK 9)
    • Stream API 增强(JDK 9)
    • Optional 增强(JDK 9 / 10 / 11)
    • String 新增方法(JDK 11)
    • HTTP Client 与 Files 增强(JDK 11)
    • 直接运行 Java 源文件 — JEP 330(JDK 11)
  • 第18章 JDK12-17新特性

    • 章节导读
    • Switch 表达式(JDK 12 预览 / JDK 14 正式)
    • 文本块 Text Blocks(JDK 13 预览 / JDK 15 正式)
    • Records 记录类(JDK 14 预览 / JDK 16 正式)
    • 密封类 Sealed Classes(JDK 15 预览 / JDK 17 正式)
    • instanceof 模式匹配(JDK 14 预览 / JDK 16 正式)
    • Switch 模式匹配 — Pattern Matching for switch(JDK 17 预览 / JDK 21 正式)
    • Helpful NPE 与 String 增强(JDK 12 / JDK 14 / JDK 15)
    • Stream 增强(JDK 12 / JDK 16)
    • 日期时间增强 — Day Period 支持(JDK 16)
  • 第19章 JDK18-21新特性

    • 章节导读
    • 虚拟线程(JDK 19 预览 / JDK 20 第二预览 / JDK 21 正式)
    • 序列集合(JDK 21 正式)
    • Switch 模式匹配(JDK 17 预览 / JDK 18 第二预览 / JDK 20 第四预览 / JDK 21 正式)
    • Record 模式匹配(JDK 19 预览 / JDK 20 第二预览 / JDK 21 正式)
    • 未命名模式与变量(JDK 21 预览 / JDK 22 正式)
  • 第20章 JDK 22-25 新特性

    • 章节导读
    • 字符串模板(JDK 22 预览 / JDK 23 第二预览 / JDK 24 第三预览)
    • Stream Gatherers(JDK 22 预览 / JDK 24 第二预览)
    • 隐式声明类与实例方法(JDK 23 预览 / JDK 24 第二预览)
    • 原始类型模式匹配(JDK 24 预览)
  • 附录

    • Java 核心知识点
    • Java SE 专业术语
    • Java特性索引(JDK 8 → 25)

JDK、JRE、JVM 详解

本章定位:深入理解 Java 技术体系中最核心的三个概念——JDK(开发工具包)、JRE(运行环境)、JVM(虚拟机)。它们是 Java "一次编写,到处运行"的技术基石,也是面试中几乎必考的送分题。大翔在技术选型会上用这三层关系说服了 CTO,白歌在代码审查时用它定位了环境问题,小崔在面试中被问到时对答如流——本章帮你达到小崔的水平。


定义速览表

组件英文全称中文译名一句话定义包含内容目标用户
JDKJava Development KitJava 开发工具包开发和运行 Java 程序的完整环境JRE + 开发工具(javac、jar、javadoc 等)Java 开发者
JREJava Runtime EnvironmentJava 运行时环境仅运行 Java 程序的最小环境JVM + 核心类库(rt.jar)最终用户
JVMJava Virtual MachineJava 虚拟机执行 Java 字节码的抽象计算机类加载器 + 运行时数据区 + 执行引擎任何运行 Java 的地方

包含关系

JDK 包含 JRE,JRE 包含 JVM。这是一个层层嵌套的结构:

关键结论:

  • JDK 面向开发者,是一个完整的开发工具包,除了能运行 Java 程序,还能编译、打包、调试
  • JRE 面向最终用户,只提供运行 Java 程序所需的最小环境
  • JVM 是 Java 语言跨平台的核心,所有 Java 程序最终都运行在 JVM 上

JDK 详解:开发者的瑞士军刀

JDK 目录结构

安装 JDK 8 后,典型的目录布局如下:

C:\Program Files\Java\jdk1.8.0_202\
├── bin/              ← 可执行文件目录
│   ├── javac.exe     ← Java 编译器(源码 → 字节码)
│   ├── java.exe      ← Java 启动器(启动 JVM 运行字节码)
│   ├── jar.exe       ← 打包工具(.class → .jar)
│   ├── javadoc.exe   ← 文档生成工具
│   ├── javap.exe     ← 字节码反编译查看器
│   ├── jdb.exe       ← 命令行调试器
│   └── ...
├── jre/              ← JDK 自带的私有 JRE
│   ├── bin/
│   │   └── java.exe  ← JRE 的 Java 启动器
│   └── lib/
│       ├── rt.jar    ← 核心类库(Runtime,约 60MB)
│       ├── charsets.jar
│       └── ...
├── lib/              ← JDK 开发工具库
│   ├── tools.jar     ← javac 等编译器核心实现
│   └── dt.jar        ← BeanInfo 等设计时库
├── include/          ← JNI 本地方法调用 C 头文件
└── src.zip           ← JDK 核心类库源码(学习利器)

私有 JRE vs 公共 JRE

JDK 8 安装时会安装两份 JRE:

类型路径用途
私有 JREjdk1.8.0_202/jre/仅供 JDK 自身工具使用(javac 等内部需要 JRE 运行)
公共 JREC:\Program Files\Java\jre1.8.0_202/供系统上所有 Java 程序使用,注册到系统 Path

公共 JRE 在安装时可取消勾选。如果只做开发,私有 JRE 已经足够。之所以存在两份,是因为 JDK 的历史设计——javac 本身是用 Java 写的,编译过程需要一个 JRE 来运行编译器。


JRE 详解:运行时的最小环境

JRE 的核心组成

JRE = JVM + 核心类库。其中核心类库以 rt.jar(Runtime JAR)的形式存在,包含了所有 Java 标准 API:

包功能典型类
java.lang语言基础类String、Object、System、Thread
java.util集合框架与工具ArrayList、HashMap、Date、Collections
java.io输入输出File、InputStream、BufferedReader
java.net网络编程Socket、URL、HttpURLConnection
java.sql数据库访问Connection、ResultSet、DriverManager
java.math高精度数学运算BigDecimal、BigInteger

rt.jar 在 JDK 8 中约 60MB,包含约 4000+ 个类。没有它,即使 JVM 能加载字节码,也无法执行任何有意义的 Java 程序(连 System.out.println 都需要 rt.jar 中的 System 类)。


JVM 详解:跨平台的核心引擎

JVM 内部架构

运行时数据区详解

区域线程共享存储内容异常
堆(Heap)是(所有线程共享)对象实例、数组OutOfMemoryError
方法区(Method Area)是类信息、常量、静态变量、JIT 编译后的代码OutOfMemoryError
Java 栈(Stack)否(每个线程独立)局部变量表、操作数栈、动态链接、返回地址StackOverflowError
程序计数器(PC)否(每个线程独立)当前线程所执行字节码的行号指示器唯一不抛 OOM 的区域
本地方法栈否(每个线程独立)本地方法(Native Method)的调用信息StackOverflowError

JIT 编译器:热点代码优化

JDK 8 默认使用分层编译(Tiered Compilation):解释执行 → C1 编译(快速优化) → C2 编译(深度优化)。方法被调用达到一定次数(默认约 10000 次)后触发 JIT 编译。


三者协作流程:从源码到运行

完整流程:

  1. 开发者使用 JDK(javac.exe)将 .java 源码编译为 .class 字节码
  2. 用户或开发者使用 JRE(java.exe)启动 JVM
  3. JVM 的类加载器读取字节码,经过校验后,结合 rt.jar 核心类库,由执行引擎解释或编译执行

完整代码示例

示例一:验证 JDK、JRE、JVM 版本与环境信息

/**
 * 场景:白歌让小崔确认三台开发机的 JDK/JRE/JVM 版本是否一致。
 * 小崔写了这个工具类,一键输出所有版本信息。
 */
public class JavaVersionChecker {
    public static void main(String[] args) {
        System.out.println("═══════════════════════════════════════");
        System.out.println("   JDK / JRE / JVM 环境信息检测");
        System.out.println("═══════════════════════════════════════\n");

        // 1. JDK 版本(开发环境版本)
        String javaVersion = System.getProperty("java.version");
        System.out.println("JDK 版本:    " + javaVersion);

        // 2. JRE 版本(运行环境版本)
        String javaRuntime = System.getProperty("java.runtime.version");
        System.out.println("JRE 版本:    " + javaRuntime);

        // 3. JVM 信息
        String jvmName = System.getProperty("java.vm.name");
        String jvmVersion = System.getProperty("java.vm.version");
        String jvmVendor = System.getProperty("java.vm.vendor");
        System.out.println("JVM 名称:    " + jvmName);
        System.out.println("JVM 版本:    " + jvmVersion);
        System.out.println("JVM 供应商:  " + jvmVendor);
        System.out.println("JVM 规范版本: " + System.getProperty("java.vm.specification.version"));

        // 4. 类路径与安装路径
        System.out.println("\nJDK 安装路径: " + System.getProperty("java.home"));
        System.out.println("类路径:       " + System.getProperty("java.class.path"));

        // 5. JVM 内存信息(堆内存默认大小)
        long maxMemory = Runtime.getRuntime().maxMemory() / (1024 * 1024);
        long totalMemory = Runtime.getRuntime().totalMemory() / (1024 * 1024);
        long freeMemory = Runtime.getRuntime().freeMemory() / (1024 * 1024);
        System.out.println("\nJVM 堆内存信息:");
        System.out.println("  最大可用: " + maxMemory + " MB");
        System.out.println("  已分配:   " + totalMemory + " MB");
        System.out.println("  空闲:     " + freeMemory + " MB");

        // 6. 判断是否 HotSpot JVM
        System.out.println("\nJVM 类型判断:");
        if (jvmName.contains("HotSpot")) {
            System.out.println("  ✓ 当前使用的是 Oracle HotSpot JVM(含 C2 JIT 编译器)");
        } else {
            System.out.println("  → 当前使用的是其他 JVM 实现");
        }

        // 7. 可用处理器数量(影响 GC 并行度)
        System.out.println("\n系统资源:");
        System.out.println("  可用处理器: " + Runtime.getRuntime().availableProcessors() + " 核");
    }
}
═══════════════════════════════════════
   JDK / JRE / JVM 环境信息检测
═══════════════════════════════════════

JDK 版本:    1.8.0_202
JRE 版本:    1.8.0_202-b08
JVM 名称:    Java HotSpot(TM) 64-Bit Server VM
JVM 版本:    25.202-b08
JVM 供应商:  Oracle Corporation
JVM 规范版本: 1.8

JDK 安装路径: C:\Program Files\Java\jdk1.8.0_202\jre
类路径:       .

JVM 堆内存信息:
  最大可用: 1820 MB
  已分配:   123 MB
  空闲:     120 MB

JVM 类型判断:
  ✓ 当前使用的是 Oracle HotSpot JVM(含 C2 JIT 编译器)

系统资源:
  可用处理器: 8 核

示例二:从 .java 到 .class —— 手动走完编译运行全链路

/**
 * 场景:小崔想知道 javac 到底做了什么,白歌让他手动编译并反编译,
 * 把 JDK → JRE → JVM 的全链路走一遍。
 * 
 * 操作步骤(在命令行中执行):
 *   步骤1(JDK 层):javac CompileDemo.java          → 生成 CompileDemo.class
 *   步骤2(JDK 层):javap -c CompileDemo.class        → 查看字节码指令
 *   步骤3(JDK 层):javap -verbose CompileDemo.class  → 查看常量池等详细信息
 *   步骤4(JRE 层):java CompileDemo                  → JVM 加载并执行
 *   步骤5(JVM 层):java -XX:+PrintCompilation CompileDemo → 查看 JIT 编译过程
 */
public class CompileDemo {
    public static void main(String[] args) {
        String message = "Hello, JVM!";
        int count = 3;

        // 这段循环在解释执行阶段会被解释器逐条执行
        // 随着调用次数增加,可能会触发 JIT 编译优化
        for (int i = 0; i < count; i++) {
            System.out.println(message + " - 第" + (i + 1) + "次");
        }

        // 打印执行环境信息,验证运行在 JVM 之上
        System.out.println("\n本程序运行在: "
            + System.getProperty("java.vm.name")
            + " v" + System.getProperty("java.vm.version"));
    }
}

命令行操作及预期输出:

步骤1 — 编译(JDK 的 javac):
  > javac CompileDemo.java
  (无输出表示编译成功,生成 CompileDemo.class)

步骤2 — 反编译查看字节码(JDK 的 javap):
  > javap -c CompileDemo.class
Compiled from "CompileDemo.java"
public class CompileDemo {
  public CompileDemo();
    Code:
       0: aload_0
       1: invokespecial #1    // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2    // String Hello, JVM!
       2: astore_1
       3: iconst_3
       4: istore_2
       5: iconst_0
       6: istore_3
       7: iload_3
       8: iload_2
       9: if_icmpge     50
      12: getstatic     #3    // Field java/lang/System.out:...
      ...
}

步骤3 — 查看 JVM 常量池与版本信息:
  > javap -verbose CompileDemo.class
  (输出包含:魔数 CA FE BA BE、主次版本号 52.0 = JDK 8、
   常量池 #1~#30、方法字节码、行号表等)

步骤4 — 运行(JRE 的 java 命令启动 JVM):
  > java CompileDemo
Hello, JVM! - 第1次
Hello, JVM! - 第2次
Hello, JVM! - 第3次

本程序运行在: Java HotSpot(TM) 64-Bit Server VM v25.202-b08

步骤5 — 观察 JIT 编译(JVM 内部):
  > java -XX:+PrintCompilation CompileDemo
  (输出 JIT 编译的方法列表,通常 main 方法不会被编译,
   但 System.out.println 的内部方法可能会被编译)

易错场景

反例一:把 JDK 目录下的 JRE 当成"唯一的 JRE"

# ❌ 错误:删除 JDK 目录后,认为系统上还有公共 JRE 可以运行程序
# 实际情况:如果安装 JDK 时取消了公共 JRE,删除 JDK 目录后系统将无法运行 Java 程序

纠正:安装 JDK 8 时会安装两份 JRE。私有 JRE 在 jdk1.8.0_202/jre/,公共 JRE 在 C:\Program Files\Java\jre1.8.0_202/。两者的 java.exe 互相独立。如果你的 Java 程序依赖公共 JRE 的 Path 注册,删除 JDK 不影响它;但如果你的 Path 只指向了 JDK 的 bin 目录,删除 JDK 后 java 命令就不可用了。

反例二:误以为 java 命令直接执行 .class 文件

# ❌ 错误:这样写会报错
> java Hello.class
错误: 找不到或无法加载主类 Hello.class

# ✅ 正确:java 命令的参数是类名,不是文件名
> java Hello

原理:java 命令启动 JVM 后,JVM 的类加载器根据完全限定类名去 classpath 中查找字节码文件。你传入的是类的名字(如 Hello),而不是文件名(Hello.class)。JVM 会自动加上 .class 后缀去搜索。

反例三:误以为 JRE = 不需要 JDK 就能开发

# ❌ 错误:只安装了 JRE,却想编译 Java 源码
> javac Hello.java
'javac' 不是内部或外部命令,也不是可运行的程序

# JRE 只包含 java 命令(运行),不包含 javac 命令(编译)

原理:javac 编译器本身就在 JDK 的 lib/tools.jar 中(JDK 9+ 改为模块),JRE 为了保持体积精简,不包含任何开发工具。开发必须 JDK,运行只需 JRE。


面试考点

Q1:JDK、JRE、JVM 分别是什么?它们之间的关系?

JDK(Java Development Kit)是 Java 开发工具包,面向开发者,包含 JRE + 开发工具(javac、jar、javadoc 等)。JRE(Java Runtime Environment)是 Java 运行时环境,面向最终用户,包含 JVM + 核心类库(rt.jar)。JVM(Java Virtual Machine)是 Java 虚拟机,是执行字节码的抽象计算机,包含类加载器、运行时数据区、执行引擎。

三者关系:JDK ⊃ JRE ⊃ JVM,是层层包含的关系。JDK 包含 JRE,JRE 包含 JVM。如果你需要开发 Java 程序,必须安装 JDK;如果只需要运行 Java 程序,JRE 就够了;任何 Java 程序最终都运行在 JVM 上。

Q2:为什么 Java 能"一次编写,到处运行"?

Java 的"一次编写,到处运行"并非在操作系统层面直接实现,而是通过引入字节码 + JVM 两层抽象:

  1. Java 源码(.java)被 JDK 的 javac 编译器编译为平台无关的字节码(.class)。字节码是对 JVM 的指令集,与 CPU 架构无关。
  2. 不同操作系统安装各自的 JVM 实现(Windows JVM、Linux JVM、macOS JVM),JVM 负责将同一份字节码翻译为本地的机器指令。
  3. 开发者只需编译一次,生成的 .class 文件可以在任何安装了 JVM 的设备上运行。

关键:JVM 充当了字节码与操作系统之间的翻译层。这也是为什么 Java 被称为"半编译半解释"语言——编译到字节码是编译,JVM 执行字节码是解释(或 JIT 编译)。

Q3:JVM 的运行时数据区包含哪些部分?各自用途?

区域线程共享性存储内容可能异常
堆(Heap)所有线程共享对象实例、数组OutOfMemoryError
方法区(Method Area)所有线程共享类信息、常量池、静态变量OutOfMemoryError
Java 栈(Stack)线程私有局部变量表、操作数栈StackOverflowError
程序计数器(PC)线程私有当前字节码行号无 OOM
本地方法栈线程私有Native 方法调用信息StackOverflowError

堆是 GC 的主要工作区域,也是 JVM 调优的核心。方法区在 HotSpot 中的实现是"永久代"(JDK 7 及以前)或"元空间"(JDK 8+)。Java 栈和程序计数器随线程创建而创建、销毁而释放。

Q4:JDK 中的私有 JRE 和公共 JRE 有什么区别?

JDK 8 安装时会安装两份 JRE:

  1. 私有 JRE(jdk目录/jre/):仅供 JDK 自身开发工具使用。因为 javac 等工具本身是用 Java 写的,编译过程需要一个 JRE 来运行编译器。
  2. 公共 JRE(C:\Program Files\Java\jre版本号/):注册到操作系统,供系统上所有 Java 程序使用。安装时可取消勾选。

如果只做开发,私有 JRE 已经足够。从 JDK 11 开始,Oracle 不再提供单独的 JRE 安装包,JDK 自带运行环境——JDK 和 JRE 的概念边界在逐渐模糊。

Q5:javac 和 java 命令分别做了什么?它们属于 JDK 还是 JRE?

javac(Java Compiler)属于 JDK,负责将 .java 源码编译为 .class 字节码。它读取源文件中的类、方法、语句,经过词法分析 → 语法分析 → 语义分析 → 字节码生成四个阶段,输出平台无关的 .class 文件。

java(Java Launcher)同时存在于 JDK 和 JRE 中,负责启动 JVM 并执行字节码。它首先创建 JVM 实例,通过类加载器加载指定的主类,校验字节码,然后从 main() 方法开始执行。

简单记忆:javac 是翻译官,把人类能看懂的 Java 代码翻译成 JVM 能看懂的字节码;java 是驾驶员,发动 JVM 这台发动机去跑字节码。

上一页
JDK安装与配置
下一页
HelloWorld程序详解