'private val'과 'private final val'이 다른 이유는 무엇입니까?


100

나는 그렇게 생각하는 데 사용 private val하고 private final val난 스칼라 기준에서 4.1 절을 볼 때까지, 동일 :

상수 값 정의는 다음 형식입니다.

final val x = e

여기서 e는 상수 표현식 (§6.24)입니다. 최종 수정자가 있어야하며 유형 주석을 제공 할 수 없습니다. 상수 값 x에 대한 참조는 자체적으로 상수 표현식으로 처리됩니다. 생성 된 코드에서 정의의 오른쪽 e로 대체됩니다.

그리고 나는 테스트를 작성했습니다.

class PrivateVal {
  private val privateVal = 0
  def testPrivateVal = privateVal
  private final val privateFinalVal = 1
  def testPrivateFinalVal = privateFinalVal
}

javap -c 산출:

Compiled from "PrivateVal.scala"
public class PrivateVal {
  public int testPrivateVal();
    Code:
       0: aload_0       
       1: invokespecial #19                 // Method privateVal:()I
       4: ireturn       

  public int testPrivateFinalVal();
    Code:
       0: iconst_1      
       1: ireturn       

  public PrivateVal();
    Code:
       0: aload_0       
       1: invokespecial #24                 // Method java/lang/Object."<init>":()V
       4: aload_0       
       5: iconst_0      
       6: putfield      #14                 // Field privateVal:I
       9: return
}

바이트 코드는 Scala Reference가 말한 것과 같습니다 : private valis not private final val.

scalac 은 다음 private val과 같이 취급 하지 private final val않습니까? 근본적인 이유가 있습니까?


28
val, a 는 이미 불변이므로 왜 finalScala에서 키워드 가 필요 합니까? 컴파일러는 왜 모든 vals를 s와 같은 방식으로 처리 할 수 final val없습니까?
Jesper 2012

참고 private범위 개질제와 동일한 의미를 갖는다 package private자바있다. 당신은 말할 수 있습니다 private[this].
Connor Doyle

5
@ConnorDoyle : 개인 패키지로? : 나는 그렇게 생각하지 않습니다 private는이 클래스의 인스턴스 만 볼 수 의미하는 private[this]동일한 인스턴스를 제외하고 - 단지이 경우 클래스 , private누군가를 허용하지 않는 값에 액세스하는 (같은 패키지 포함).
Make42

답변:


81

따라서 이것은 추측 일 뿐이지 만 오른쪽에 리터럴이있는 최종 정적 변수가 상수로 바이트 코드에 인라인되는 것은 Java에서 계속되는 성가심이었습니다. 이로 인해 성능상의 이점이 확실히 발생하지만 "상수"가 변경되면 정의의 이진 호환성이 깨집니다. 값을 변경해야하는 최종 정적 변수를 정의 할 때 Java 프로그래머는 메서드 또는 생성자로 값을 초기화하는 것과 같은 해킹에 의존해야합니다.

Scala의 val은 Java 의미에서 이미 최종입니다. Scala의 디자이너는 "상수 값을 인라인 할 수있는 권한"을 의미하기 위해 중복 수정 자 final을 사용하는 것 같습니다. 따라서 Scala 프로그래머는 해킹에 의존하지 않고도이 동작을 완벽하게 제어 할 수 있습니다. 인라인 상수, 절대 변경되지 않아야하지만 빠른 값을 원하면 "final val"을 작성합니다. 바이너리 호환성을 깨지 않고 값을 유연하게 변경하려면 "val"만 있으면됩니다.


9
그렇습니다. 그것이 비공개가 아닌 val의 이유입니다. 그러나 private val은 분명히 다른 클래스에 인라인 될 수없고 같은 방식으로 호환성을 깨뜨릴 수 없습니다.
Alexey Romanov 2012

3
로 변경할 때 바이너리 호환성 문제 private valprivate final val있습니까?
양 보

1
@ steve-waldman 실례 val합니다. 두 번째 단락에서 말씀 하셨나요?
양 보

1
- 다음은 바이너리 호환성에 관한 자바에서 최종 정적 변수에 대한 세부 사항입니다 docs.oracle.com/javase/specs/jls/se7/html/...는
, 둘다 메단

8

여기서 혼동은 불변성과 최종의 의미를 결합하는 데서 발생한다고 생각합니다. vals는 자식 클래스에서 재정의 될 수 있으므로 명시 적으로 표시되지 않는 한 final로 처리 될 수 없습니다.

@Brian REPL은 라인 수준에서 클래스 범위를 제공합니다. 보다:

scala> $iw.getClass.getPackage
res0: Package = package $line3

scala> private val x = 5
<console>:5: error: value x cannot be accessed in object $iw
  lazy val $result = `x`

scala> private val x = 5; println(x);
5

1
에 대해 이야기하고 private val있습니다. 재정의 할 수 있습니까?
양 보

아니요, 개인 값은 무시할 수 없습니다. 하위 클래스에서 동일한 이름을 가진 다른 private val을 재정의 할 수 있지만 동일한 이름을 가진 완전히 다른 val입니다. (이전 참조에 대한 모든 참조는 여전히 이전 참조를 참조합니다.)
aij

1
클래스의 컨텍스트에 전혀 속하지 않고 인터프리터에서 최종 val (또는 최종 var)을 만들 수 있기 때문에 이것은 재정의 동작이 아닌 것 같습니다.
nairbv 2014
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.