diff --git a/new/master-java11/05.md b/new/master-java11/05.md index fac37ec5944f80b50e5fb2b475c39cb3b49c3014..42048899e35c4dc4437f2aa99c4c1f7e35f3d50d 100644 --- a/new/master-java11/05.md +++ b/new/master-java11/05.md @@ -571,7 +571,7 @@ public class DependencyTest { 正如您在本章前面所读到的,大多数内部 API 都是强封装的。如前所述,在更新源代码时,您可能会寻找替换 API。当然,这并不总是可行的。您可以在运行时使用`--add-opens`选项、使用`--add-exports`选项和`--permit-illegal-access`命令行选项来采取另外三种方法。让我们看看每一个选项。 -# --add 打开选项 +# `--add-opens`选项 您可以使用`--add-opens`运行时选项来允许您的代码访问非公共成员。这可以称为**深反射**。进行这种深度反思的图书馆能够访问所有成员,包括私人和公共。要授予这种类型的代码访问权限,可以使用`--add-opens`选项。语法如下: @@ -581,7 +581,7 @@ public class DependencyTest { 这允许给定的模块打开指定的包。使用此选项时,编译器不会产生任何错误或警告。 -# --add exports 选项 +# `--add-exports`选项 您可以使用`--add-exports`来破坏封装,这样您就可以使用默认为不可访问的内部 API。语法如下: @@ -599,7 +599,7 @@ public class DependencyTest { 只有在认为绝对必要的情况下才应使用`--add-exports`命令行选项。除短期解决方案外,不建议使用此选项。常规使用它的危险在于,对引用的内部 API 的任何更新都可能导致代码无法正常工作。 -# --permit 非法访问选项 +# `--permit-illegal-access`选项 打破封装的第三个选择是使用`--permit-illegal-access`选项。当然,谨慎的做法是与第三方库创建者核实是否有更新的版本。如果这不是一个选项,那么您可以使用`--permit-illegal-access`非法访问要在类路径上实现的操作。由于这里的操作非常非法,每次发生这些操作时,您都会收到警告。 @@ -707,7 +707,7 @@ Java 中删除的另外两个内容如下: # 序列化小程序 -Java 不再支持将 Applet 作为序列化对象进行部署。过去,applet 被部署为序列化对象,以补偿压缩速度慢和 JVM 性能问题。在当前的 Java 平台上,压缩技术是先进的,JVM 具有良好的性能。 +Java 不再支持将 Applet 作为序列化对象进行部署。过去,Applet 被部署为序列化对象,以补偿压缩速度慢和 JVM 性能问题。在当前的 Java 平台上,压缩技术是先进的,JVM 具有良好的性能。 如果尝试将小程序部署为序列化对象,则在启动小程序时,对象属性和参数标记将被忽略。从 Java9 开始,您可以使用标准部署策略部署小程序。 @@ -721,7 +721,7 @@ JNLP 规范在 Java9 中进行了更新。以下章节详细介绍了四个具 # 嵌套资源 -以前支持将组件扩展与 Java 或 j2se 元素中的嵌套资源一起使用,但规范中没有对此进行说明。规范现在已经更新以反映这种支持。先前的规范如下: +以前支持将组件扩展与 Java 或 J2SE 元素中的嵌套资源一起使用,但规范中没有对此进行说明。规范现在已经更新以反映这种支持。先前的规范如下: *不能将 Java 元素指定为资源的一部分。* @@ -729,7 +729,7 @@ JNLP 规范在 Java9 中进行了更新。以下章节详细介绍了四个具 组件扩展中的 Java 元素不会控制所使用的 Java 版本,但可以使用包含嵌套资源元素的 Java 版本,并且只有在使用与第 4.6 节中指定的给定版本匹配的 Java 版本时,才可以使用这些资源。 -这个特定的更改确保扩展 JLP 文件必须具有 Java 或 j2se 资源,并且这些资源不会指定使用什么 JRE。使用指定版本时允许嵌套资源。 +这个特定的更改确保扩展 JLP 文件必须具有 Java 或 J2SE 资源,并且这些资源不会指定使用什么 JRE。使用指定版本时允许嵌套资源。 # FX XML 扩展 @@ -904,7 +904,7 @@ Maven 可以与 Eclipse(M2Eclipse)、JetBrains IntelliJ IDEA 和 netbeansIDE * 您可以很容易地解析 Maven 依赖关系(您可以直接从 Eclipse 执行此操作,而不必安装本地 Maven 存储库) * 您可以自动下载所需的依赖项(从远程 Maven 存储库) * 您可以使用软件向导创建新的 Maven 项目,创建`pom.xml`文件,并为普通 Java 项目启用 Maven 支持 -* Use 可以对 Maven 的远程存储库执行快速的依赖性搜索 +* 您可以对 Maven 的远程存储库执行快速的依赖性搜索 # 获取 Eclipse IDE diff --git a/new/master-java11/06.md b/new/master-java11/06.md index 6d7ce07f45a67ac23f69a9a10c19bd3f5d987087..01f3a6d9cbabeb86971c3d107c22f267e18b5594 100644 --- a/new/master-java11/06.md +++ b/new/master-java11/06.md @@ -65,7 +65,7 @@ jshell | `/edit` | 使用此命令,您可以使用`name`或`id`引用编辑源条目语法如下:`/edit ` | | `/env` | 这个强大的命令允许您查看或更改评估上下文语法如下:`/env [-class-path ]  [-module-path ]  [-add-modules ]` | | `/exit` | 此命令用于退出 JShell。语法是简单的`/exit`,没有任何可用的选项或参数。 | -| `/history` | history 命令提供您所键入内容的历史记录。语法是简单的`/history`,没有任何可用的选项或参数。 | +| `/history` | `history`命令提供您所键入内容的历史记录。语法是简单的`/history`,没有任何可用的选项或参数。 | | `/` | 此命令用于通过引用`id`重新运行以前的代码段。语法如下:`/`您也可以使用`/-`引用前`n`个代码段来运行特定的代码段。 | | `/imports` | 可以使用此命令列出导入的项目。语法为`/imports`,不接受任何选项或参数。 | | `/list` | 此命令将列出您键入的源代码。语法如下:`/list [ | -all | -start]` | @@ -176,7 +176,7 @@ jshell ![](img/7e1da0de-02ab-4b9c-8a69-8452b355def4.png) -作为一个例子,让我们浏览一下 truncation 设置,该设置要求在每个输出行上显示多少个字符。使用`/set truncation`命令,如下面的屏幕截图所示,显示当前的截断设置: +作为一个例子,让我们浏览一下`truncation`设置,该设置要求在每个输出行上显示多少个字符。使用`/set truncation`命令,如下面的屏幕截图所示,显示当前的截断设置: ![](img/d6c42080-2734-48f5-a805-d520602e9154.png) diff --git a/new/master-java11/07.md b/new/master-java11/07.md index 61d3015b84d9f599fe73ededd7bf05ede6233da1..53c1afd0fc31f368b4fd972df29e1f786806472e 100644 --- a/new/master-java11/07.md +++ b/new/master-java11/07.md @@ -88,7 +88,7 @@ JVM 可以使用几种垃圾收集算法或类型。在本节中,我们将介 # 标记和扫描 -Java 的初始垃圾收集算法 mark and sweep 使用了一个简单的两步过程: +Java 的初始垃圾收集算法标记清除使用了一个简单的两步过程: 1. 第一步,标记,是遍历所有具有可访问引用的对象,将这些对象标记为活动对象 @@ -187,7 +187,7 @@ G1 垃圾收集算法还根据要收集的垃圾最多的区域来确定区域 | 您可以使用此命令在备注阶段之前强制年轻的集合。 | `-XX:+CMSScavengeBeforeRemark` | | 如果使用的 Eden 低于阈值,则使用此选项可防止出现计划注释。 | `-XX:+CMSScheduleRemark\EdenSizeThreshold` | | 设置您希望 CMS 尝试和安排备注暂停的 Eden 占用百分比。 | `-XX:CMSScheduleRemark\EdenPenetration=20` | -| 至少在新生代的入住率达到您想要安排备注的 1/4(在我们右边的示例中)之前,您就要在这里开始对 Eden top 进行采样。 | `-XX:CMSScheduleRemark\SamplingRatio=4` | +| 至少在新生代的入住率达到您想要安排备注的 1/4(在我们右边的示例中)之前,您就要在这里开始对 Eden 顶部进行采样。 | `-XX:CMSScheduleRemark\SamplingRatio=4` | | 备注后可选择`variant=1`或`variant=2`验证。 | `-XX:CMSRemarkVerifyVariant=1` | | 选择使用并行算法进行年轻空间的收集。 | `-XX:+UseParNewGC` | | 允许对并发阶段使用多个线程。 | `-XX:+CMSConcurrentMTEnabled` | @@ -283,7 +283,7 @@ public class GCVerificationTest { 除了使用`System.gc()`方法调用垃圾收集器之外,还有一种替代方法。在我们的例子中,我们可以使用`myRuntime.gc()`,我们早期的单例例子。 -# finalize()方法 +# `finalize()`方法 你可以把 Java 的垃圾收集器想象成死亡贩子。当它从记忆中删除某些东西时,它就消失了。这个所谓的死亡贩子并非没有同情心,因为它为每个方法提供了他们最后的遗言。对象通过`finalize()`方法给出他们的最后一句话。如果一个对象有一个`finalize()`方法,垃圾收集器会在移除该对象和释放相关内存之前调用它。该方法不带参数,返回类型为`void`。 @@ -640,7 +640,7 @@ Java9 日志框架支持三种类型的输出: # gc 标签 -我们可以使用带有`-Xlog`选项的`gc`标记来通知 JVM 在 info 级别只记录`gc`标记的项。您还记得,这类似于使用`-XX:+PrintGC`。使用这两个选项,JVM 将为每个垃圾收集操作记录一行。 +我们可以使用带有`-Xlog`选项的`gc`标记来通知 JVM 在`info`级别只记录`gc`标记的项。您还记得,这类似于使用`-XX:+PrintGC`。使用这两个选项,JVM 将为每个垃圾收集操作记录一行。 值得注意的是,`gc`标签并非单独使用,而是建议与其他标签一起使用。 @@ -658,7 +658,7 @@ log_(Tag1[,...])(fmtstr, ...) log_debug(gc, classloading)("Number of objects loaded: %d.", object_count) ``` -下面的示例 skeleton`log`宏显示了如何使用新的 Java 日志框架来创建脚本,以提高日志记录的逼真度: +下面的示例框架`log`宏显示了如何使用新的 Java 日志框架来创建脚本,以提高日志记录的逼真度: ```java LogHandle(gc, rt, classunloading) log; @@ -705,18 +705,18 @@ if (log.is_trace()) { 正如本章前面提到的,G1 垃圾收集器自 Java9 以来一直是默认的垃圾收集器。G1 垃圾收集器的效率之一是它使用并发垃圾收集而不是完全收集。有时会实现完全垃圾收集,通常是并发垃圾收集速度不够快。注意,在 Java9 之前,并行收集器是默认的垃圾收集器,是一个并行的完全垃圾收集器。 -对于 Java10,g1full 垃圾回收器被转换为 parallel,以减轻对使用 full 垃圾回收的开发人员的任何负面影响。将用于 G1 完全垃圾回收的 mark-week 压缩算法并行化。 +对于 Java10,G1Full 垃圾回收器被转换为并行,以减轻对使用完全垃圾回收的开发人员的任何负面影响。将用于 G1 完全垃圾回收的 mark-week 压缩算法并行化。 # Epsilon–任意低开销 GC -Java 的最新版本 version11 附带了一个负责内存分配的被动 GC。这个 GC 的被动性质(称为 epsilongc)表明它不执行垃圾收集;相反,它继续分配内存,直到堆上没有剩余空间为止。这时,JVM 关闭。 +Java 的最新版本 11 附带了一个负责内存分配的被动 GC。这个 GC 的被动性质(称为 EpsilonGC)表明它不执行垃圾收集;相反,它继续分配内存,直到堆上没有剩余空间为止。这时,JVM 关闭。 为了启用 Epsilon GC,我们使用以下任一方法: * `-XX:+UseEpsilonGC` * `-XX:+UseNoGC` -epsilongc 的使用主要出现在测试中,由于缺乏垃圾收集,它的开销很低,提高了测试效率 +EpsilonGC 的使用主要出现在测试中,由于缺乏垃圾收集,它的开销很低,提高了测试效率 # 长期存在的问题 @@ -750,7 +750,7 @@ public class GarbageCollectionExperimentOne { } ``` -如在代码注释中所示,一旦 string object 引用变量设置为`null`,在本例中使用`junk = null;`语句,对象就可以进行垃圾收集。 +如在代码注释中所示,一旦字符串对象引用变量设置为`null`,在本例中使用`junk = null;`语句,对象就可以进行垃圾收集。 在我们的下一个示例中,我们将通过将对象的引用变量设置为指向另一个对象来放弃该对象。正如您在以下代码中看到的,这导致第一个对象可用于垃圾收集: diff --git a/new/master-java11/08.md b/new/master-java11/08.md index 92fd45fb20d066509f70b52c45ce28aeaa3cbfe2..9f2e30499b206474724007768d9c80c86f6bcc7a 100644 --- a/new/master-java11/08.md +++ b/new/master-java11/08.md @@ -37,7 +37,7 @@ IDE 软件包就足够了。来自 JetBrains 的 IntelliJ IDEA 用于与本章 Oracle 的文档表明,最理想的 JMH 用例是使用依赖于应用程序 JAR 文件的 Maven 项目。他们进一步建议微标记通过命令行进行,而不是从 IDE 中进行,因为这可能会影响结果。 -Maven,也称为 apachemaven,是一个项目管理和理解工具,我们可以使用它来管理我们的应用程序项目构建、报告和文档。 +Maven,也称为 ApacheMaven,是一个项目管理和理解工具,我们可以使用它来管理我们的应用程序项目构建、报告和文档。 为了使用 JMH,我们将使用字节码处理器(注释)来生成基准代码。 @@ -51,7 +51,7 @@ Maven,也称为 apachemaven,是一个项目管理和理解工具,我们可 # 动手实验 -现在我们已经安装了 eclipseoxygen,您可以运行一个快速测试来确定 JMH 是否在您的开发计算机上工作。首先创建一个新的 Maven 项目,如以下屏幕截图所示: +现在我们已经安装了 EclipseOxygen,您可以运行一个快速测试来确定 JMH 是否在您的开发计算机上工作。首先创建一个新的 Maven 项目,如以下屏幕截图所示: ![](img/4889a0b4-6ec1-4e9a-b8e8-d7b61065eaf9.png) @@ -97,7 +97,7 @@ JMH 测试结果 # Maven 微基准 -开始使用 JMH 的一种方法是使用 jmhmaven 原型。第一步是创建一个新的 JMH 项目。在我们系统的命令提示符下,我们将输入`mvn`命令,然后输入一组长参数,以创建一个新的 Java 项目和必要的 Maven`pom.xml`文件: +开始使用 JMH 的一种方法是使用 JMHMaven 原型。第一步是创建一个新的 JMH 项目。在我们系统的命令提示符下,我们将输入`mvn`命令,然后输入一组长参数,以创建一个新的 Java 项目和必要的 Maven`pom.xml`文件: ```java mvn archetype:generate -DinteractiveMode=false -DarchetypeGroupId=org.openjdk.jmh -DarchetypeArtifactId=jmh-java-benchmark-archetype -DgroupId=com.packt -DartifactId=chapter8-benchmark -Dversion=1.0 @@ -334,7 +334,7 @@ if (value != null) { . . . ``` -在我们前面的示例中,由于变量值永远不会等于 null,因此永远不会到达标识为死代码的行。在条件语句`if`计算变量之前,它被设置为`10`。 +在我们前面的示例中,由于变量值永远不会等于`null`,因此永远不会到达标识为死代码的行。在条件语句`if`计算变量之前,它被设置为`10`。 问题是,为了消除死代码,有时可以删除基准测试代码。 @@ -355,7 +355,7 @@ int newValue = 3190; 对于这个陷阱,有一个建议的策略: -* 使用 jmhAPI 支持来确保您的基准测试代码不会被消除 +* 使用 JMH API 支持来确保您的基准测试代码不会被消除 # 运行间差异 diff --git a/new/master-java11/09.md b/new/master-java11/09.md index f416cbf9e715adfa0c28401c1c8c23bcba416e22..090d350bb9e4861a6f2d825eea6d4536aecfc184 100644 --- a/new/master-java11/09.md +++ b/new/master-java11/09.md @@ -8,7 +8,7 @@ * 引入流程 * 使用`ProcessHandle`接口 -* 查看示例 process controller 应用程序 +* 查看示例进程控制器应用程序 # 技术要求 @@ -34,7 +34,7 @@ IDE 软件包就足够了。来自 JetBrains 的 IntelliJ IDEA 用于与本章 程序可以准备在收到此类请求时停止。例如,Java 应用程序可以添加一个调用`Runtime.getRuntime().addShutdownHook(Thread t)`方法的`Thread`对象。传递的线程应该在进程被要求停止时启动,这样线程就可以执行程序退出前必须执行的所有任务。不幸的是,不能保证线程会真正启动,这取决于实际的实现。 -# 使用 ProcessHandle 接口 +# 使用`ProcessHandle`接口 Java9 中引入了两个支持处理操作系统进程的新接口-`ProcessHandle`和`ProcessHandle.Info`。 @@ -159,7 +159,7 @@ public class ChildLister { 列出子进程与列出子进程非常相似,但是如果我们调用`processHandle.descendants()`方法,那么`Stream`将包含所有子进程以及这些进程的子进程,依此类推。 -以下程序以命令行参数启动命令提示,以便它们也生成另一个终止的【T0”: +以下程序以命令行参数启动命令提示,以便它们也生成另一个终止的`cmd.exe`: ```java import java.io.IOException; @@ -286,7 +286,7 @@ public class TerminateAProcessAfterWaiting { 示例代码将睡眠时间设置为 10 秒。这是一个更明显的时间段。运行两次代码并删除破坏进程的行会导致打印速度慢得多。实际上,测量和打印的运行时间也会显示终止进程会产生影响。 -# 查看示例 process controller 应用程序 +# 查看示例进程控制器应用程序 最后一节提供了一个示例过程控制应用程序来演示本章的内容。应用程序的功能非常简单。它从一系列配置文件参数中读取如何启动某些进程,然后,如果其中任何进程停止,它将尝试重新启动进程。 @@ -390,7 +390,7 @@ public class ParamsAndHandle { } ``` -由于该类与使用它的`ControlDaemon`类紧密相连,因此没有与该字段相关联的 mutator 或 accessor。我们把这两个类看作是在同一个封装边界内的东西。`toHandle () `方法就在那里,所以我们可以将它用作方法句柄,我们将在第 10 章、“细粒度栈跟踪”中看到。 +由于该类与使用它的`ControlDaemon`类紧密相连,因此没有与该字段相关联的更改器或访问器。我们把这两个类看作是在同一个封装边界内的东西。`toHandle () `方法就在那里,所以我们可以将它用作方法句柄,我们将在第 10 章、“细粒度栈跟踪”中看到。 # 控制守护进程 diff --git a/new/master-java11/10.md b/new/master-java11/10.md index 5e9302d12a23617cae3fcc7263c738c037531705..01231ff868926f95d0f77dbd885868ef5587f842 100644 --- a/new/master-java11/10.md +++ b/new/master-java11/10.md @@ -125,7 +125,7 @@ public class CheckEligibility { ![](img/8da943bd-0406-4257-8bcb-2707259cb2a4.png) -StackFrame 在库中找到的类 +`StackFrame`在库中找到的类 # 示例–为呼叫者获取记录器 @@ -154,7 +154,7 @@ public class Labrador { 接下来,我们来看看`StackWalker`的细节。 -# 与 StackWalker 合作 +# 与`StackWalker`合作 在本节中,您将熟悉如何使用`StackWalker`。本节将探讨以下主题: @@ -163,7 +163,7 @@ public class Labrador { * 访问类 * 步行法 -# 正在获取 StackWalker 的实例 +# 正在获取`StackWalker`的实例 要遍历栈元素,我们需要一个`StackWalker`的实例。为此,我们调用`getInstance()`方法。如图所示,此方法有四个重载版本: @@ -172,7 +172,7 @@ public class Labrador { * `static StackWalker getInstance(Set options)` * `static StackWalker getInstance(Set options, int estimateDepth)` -第一个版本不接受任何参数,并返回一个`StackWalker`实例,让我们遍历正常的栈帧。这通常是我们感兴趣的。该方法的其他版本接受一个或多个`StackWalker.Option`值。顾名思义,enum`StackWalker.Option`在`StackWalker`类中,有三个值: +第一个版本不接受任何参数,并返回一个`StackWalker`实例,让我们遍历正常的栈帧。这通常是我们感兴趣的。该方法的其他版本接受一个或多个`StackWalker`类中的`StackWalker.Option`枚举,有三个值: * `RETAIN_CLASS_REFERENCE` * `SHOW_REFLECT_FRAMES` @@ -180,19 +180,19 @@ public class Labrador { # 枚举选项 -`RETAIN_CLASS_REFERENCE`、`SHOW_REFLECT_FRAMES`和`SHOW_HIDDEN_FRAMES`enum 选项具有自描述性名称,下面将对其进行说明。 +`RETAIN_CLASS_REFERENCE`、`SHOW_REFLECT_FRAMES`和`SHOW_HIDDEN_FRAMES`枚举选项具有自描述性名称,下面将对其进行说明。 -# 保留等级参考 +# `RETAIN_CLASS_REFERENCE` -如果我们指定第一个选项 enum constant,`RETAIN_CLASS_REFERENCE`作为`getInstance()`方法的参数,那么返回的实例将授予我们访问各个栈在遍历期间引用的类的权限。 +如果我们指定第一个选项的枚举常量,`RETAIN_CLASS_REFERENCE`作为`getInstance()`方法的参数,那么返回的实例将授予我们访问各个栈在遍历期间引用的类的权限。 -# 显示\u 反射\u 帧 +# `SHOW_REFLECT_FRAMES` -`SHOW_REFLECT_FRAMES`enum 常量将生成一个 walker,其中包含来自某个反射调用的帧。 +`SHOW_REFLECT_FRAMES`枚举常量将生成一个遍历器,其中包含来自某个反射调用的帧。 -# 显示隐藏的帧 +# `SHOW_HIDDEN_FRAMES` -最后,enum constant 选项`SHOW_HIDDEN_FRAMES`将包括所有隐藏帧,其中包含反射调用以及为 Lambda 函数调用生成的调用帧。 +最后,枚举常量选项`SHOW_HIDDEN_FRAMES`将包括所有隐藏帧,其中包含反射调用以及为 Lambda 函数调用生成的调用帧。 下面是反射和隐藏框架的简单演示: @@ -348,7 +348,7 @@ stackwalker/packt.Main.main(Main.java:8) 在大多数情况下,它的效率较低,因为它强制`StackWalker`实例获取栈跟踪的所有元素,这样`forEach()`方法就可以遍历每个元素到最后。如果我们知道我们不会遍历栈跟踪到最后,我们应该使用`walk()`方法,即以惰性的方式访问栈,从而为性能优化留下更多的空间。 -`StackWalker`类有`walk()`方法,这是使其成为 walker 的定义方法。该方法接受由`StackWalker`调用的函数。`walk()`方法的返回值将是函数返回的对象。函数的参数是传递栈帧的`Stream`。第一帧是包含`walk()`方法调用的帧,下一帧是调用包含`walk()`方法调用的帧,依此类推。 +`StackWalker`类有`walk()`方法,这是使其成为遍历器的定义方法。该方法接受由`StackWalker`调用的函数。`walk()`方法的返回值将是函数返回的对象。函数的参数是传递栈帧的`Stream`。第一帧是包含`walk()`方法调用的帧,下一帧是调用包含`walk()`方法调用的帧,依此类推。 该函数可用于根据来自流的`StackFrame`对象计算一些值,并决定调用方是否有资格调用我们的代码。 @@ -371,7 +371,7 @@ public static void itIsNotCallBack() { } ``` -我们所做的只是直接从 walker 调用返回流,然后遍历流,然后执行相同的计算。我们的结果是`IllegalStateException`例外,而不是资格检查。 +我们所做的只是直接从遍历器调用返回流,然后遍历流,然后执行相同的计算。我们的结果是`IllegalStateException`例外,而不是资格检查。 原因是`StackWalker`的实现高度优化。它不会复制整个栈来为流提供源信息。它是从实际的,活生生的栈中工作的。为此,必须确保在使用流时不修改栈。这与迭代集合时更改集合可能得到的`ConcurrentModificationException`异常非常相似。如果我们在调用栈中向上传递流,然后想要从中获取`StackFrame`,那么流将尝试从早已消失的栈帧中获取信息,因为我们从它所属的方法返回。这样,`StackWalker`就不会生成整个栈的快照,而是从实际栈开始工作,并且必须确保所需的栈部分不会更改。我们可以从函数中调用方法,这样我们可以在调用链中更深入地挖掘,但是在流被使用时,我们不能得到更高的值。