密封类构造函数传值的使用细节；_nl_密封类用来表示受限的类继承结构：当一个值为有限几种的类型、而不能有任何其他类型时。在某种意义上，他们是枚举类的扩展：枚举类型的值集合也是受限的，但每个枚举常量只存在一个实例，而密封类的一个子类可以有可包含状态的多个实例。_nl_密封类虽然非常实用，经常能成为我们多 type 的绝佳搭配，但其中却藏着一些使用的小细节，比如 构造函数传值所导致的损耗问题。_nl_如题, 我们有一个公用的属性 sum ,为了便于复用，我们将其抽离到 Fruit 类构造函数中，让子类便于初始化时传入，而不用重复显式声明。_nl_上述代码看着似乎没什么问题？按照传统的操作习惯，我们也很容易写出这种代码。_nl_显然这并不是我们愿意看到的，我们接下来对其进行改造一下。_nl_我们对上述示例进行稍微改造，如下所示：_nl_如题，我们将 sum 变量定义为了一个抽象变量，从而让子类自行实现。对比字节码可以发现，相比最开始的示例，我们的父类 Fruit 中减少了一个 sum 变量的损耗。_nl_如上所示，我们增加了一个名为 IFruit 的接口，并让 密封父类 实现了这个接口，子类默认在构造函数中实现该属性即可。_nl_观察字节码可发现,我们的父类一干二净，无论是从包大小还是性能，我们都避免了没必要的损耗。_nl_栈帧： 指的是虚拟机在进行方法调用和方法执行时的数据结构，每一个栈帧里都包含了相应的数据，比如 局部参数，操作数栈等等。 Jvm在执行方法时，每执行一个方法会产生一个栈帧，随后将其保存到我们当前线程所对应的栈里，方法执行完毕时再将此方法出栈， 所以内联后就相当于省了一个栈帧调用。_nl_如果上述描述中，你只记住了后半句，降低栈帧 ，那么此时你可能已经陷入了一个使用陷阱？_nl_上面我们提到了，内联是会将代码移动到调用处，降低 一层栈帧，但这个性能提升真的大吗？ 再仔细想想，移动到调用处，移动到调用处。这是什么概念呢？_nl_假设我们某个方法里代码只有两行(我想不会有人会某个方法只有一行吧)，这个方法又被好几处调用，内联是提高了调用性能，毕竟节省了一次栈帧,再加上方法行数少(暂时抛弃虚拟机优化这个底层条件)。_nl_但如果方法里代码有几十行？每次调用都会把代码内联过来，那调用处岂不爆炸，带来的包大小影响某种程度上要比内联成本更高！_nl_如下图所示，我们对上述示例做一个论证：_nl_具体对比图如上所示，不难发现，我们的调用处已经被替换为原方法，相应的 lambda 也被消除了，从而显著减少了性能损耗。_nl_因为内联函数会将方法函数移动到调用处，会增加调用处的代码量，所以对于较长的方法应该避免使用；_nl_上述代码看着似乎没什么问题，但如果我们将其转为字节码后再看一看：_nl_让我们再回到伴生对象本身，我们真的一定需要它吗？_nl_这种写法属于以增加静态类的方式避免伴生对象的内存损耗，如果你的场景是单独的增加一个 tag, 那么这种写法比较推荐。_nl_apply 作为开发中的常客，为我们带来了不少便利。其内部实现也非常简单，将我们的对象以函数的形式返回，this 作为接收者。从而以一种优雅的方式实现对对象方法、属性的调用。_nl_但经常会看到有不少同学在构造者模式中写出以下代码,使用 apply 直接作为返回值，这种方式固然看着优雅，性能也几乎没有差别。但这种场景而言，如果我们注意到其字节码，会发现其并不是最佳之选。_nl_如上所示，使用了 apply 后，我们的字节码中增加了多余步骤，相比不使用的，包大小会有一点影响，性能上几乎毫无差距。_nl_如果你的方法中需要对某个对象操作多次，比如调用其方法或者属性，那么此时可以使用 apply ,反之，如果次数过少，其实你并不需要 apply 的优雅。_nl_作用也相对直接，如果我们有某个对象或字段，我们可能只想使用时再初始化，此时就可以先声明，等到使用时再去初始化，并且这个初始化过程默认也是线程安全(不特定使用NONE)。这样的好处就是性能优势，我们不必应用或者页面加载时就初始化一切，相比过往的 var xx = null ，这种方式一定程度上也更加便捷。