4

次のことを考えてみましょう。

object Foo {
  val BUFFER_SIZE = 1024
}

class Foo {
  .
  .
  .

  val buffer = new Array[Byte](Foo.BUFFER_SIZE)

これは冗長すぎて、Java の static (final) 変数に比べて洗練されていないように見えます。特に、定数の定義と使用法が離れすぎてコードをすぐに理解できないためです。私が欲しいのは次のようなものです:

class Foo {
  val BUFFER_SIZE = 1024

  val buffer = new Array[Byte](BUFFER_SIZE)

問題は、Scala コンパイラは Foo のすべてのインスタンスに対して BUFFER_SIZE をインスタンス化して時間とスペースを浪費しないほどスマートなのかということです。それとも最初のものと一緒に行くべきですか?

4

2 に答える 2

6

TLDR: いいえ、あまり良くありませんが、コンパイラをガイドすることはできます。

そして、チェックするのは簡単です (コードを test.scala に入れました):

scalac test.scala 
javap Foo.class
// Compiled from "test.scala"
// public class Foo {
//   public int BUFFER_SIZE();
//   public byte[] buffer();
//   public Foo();
// }

したがって、val は getter メソッドになります。実際のバイトコードを見てみましょう。

javap -c Foo.class
Compiled from "test.scala"
public class Foo {
  public int BUFFER_SIZE();
    Code:
       0: aload_0       
       1: getfield      #15                 // Field BUFFER_SIZE:I
       4: ireturn       

  // .... irrelevant parts

ご覧のとおりgetfield、すべてのクラス インスタンスに個別のインスタンスが存在することを意味するコードがあります (getstatic静的変数へのアクセスを意味します)。高度に最適化されたコードは次のようになります

public final int BUFFER_SIZE();
    Code:
       0: sipush        1024
       3: ireturn 

final修飾子で BUFFER_SIZE をマークすると生成されます。

class Foo {
  final val BUFFER_SIZE = 1024

  val buffer = new Array[Byte](BUFFER_SIZE)
}

private[this]@ghikが言ったようにフィールドにプレフィックスを付けると、同様にうまくいきます。違いは、final単純なコードでゲッターを生成するのに対し、private[this]値を直接インライン化することです。

于 2013-10-04T20:22:14.650 に答える
2

このように最適化されることはありません。これは、外部 (Java など) から利用できる必要があるメンバーであるためです。

(将来的に)最適化される可能性がある唯一の状況は、次のように宣言されている場合ですprivate[this]

class Foo {
  private[this] val BUFFER_SIZE = 1024
  val buffer = new Array[Byte](BUFFER_SIZE)
}

とにかく、コンパニオン オブジェクトを使用する方法だと思います。

于 2013-10-04T20:21:11.397 に答える