문제

Let's consider the following:

object Foo {
  val BUFFER_SIZE = 1024
}

class Foo {
  .
  .
  .

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

This is too verbose and doesn't seem to be elegant compared with Java's static (final) variable, especially because the definition and the usage of the constant are too far apart to understand the code immediately. What I want is something like this:

class Foo {
  val BUFFER_SIZE = 1024

  val buffer = new Array[Byte](BUFFER_SIZE)

The question is, is the Scala compiler smart enough to not instantiate BUFFER_SIZE for every instance of Foo to waste time and space? Or should go with the first one?

도움이 되었습니까?

해결책

TLDR: No, it is not so good, but you can guide the compiler.

And it's easy to check (I put the code into test.scala):

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

So val ends up to be a getter method. Now let's look at the actual bytecode:

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

As you can see there is a getfield code that means there will be distinct instance for every class instance (versus getstatic which means access to static variable). Highly optimized code would look like

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

which will be produced if you mark BUFFER_SIZE with final modifier:

class Foo {
  final val BUFFER_SIZE = 1024

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

Prefixing field with private[this] as @ghik said will do the trick as well. The difference is that final produces getter with trivial code, whereas private[this] directly inlines value.

다른 팁

It will never be optimized out like this, because it's a member that has to be available from outside (e.g. from Java).

The only situation when it may be optimized out (in the future) is when it's declared as private[this]:

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

Anyway, I would still say that the way to go is to use companion object.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top