package sample.package;
class Class{
int method(int... parameters){
int a = 4;
statement;
statement;
...
}
...
}
위와 같이 Class 라는 이름을 가진 클래스가 있다. 이것을 다음과 같이 정리해보았다.
[ ${name}, (${value},${type or $signature}, ${namespace(scope)}, ${life time} ) ]
[ Class , { (...), ( sample.package.Class ), ( sample.package ), ( While the application is running ) } ]
Class 는 클래스 블록 코드이며, sample.package.Class 가 시그니쳐이다. Class 의 namespace, 즉, scope 는 sample.package 이다. 마지막으로 라이프 타임은 어플리케이션이 실행되는 동안이다.
[ method , { (...), ( method(int\[]...) ), ( sample.package.Class ), ( Instance of Class ) } ]
method 는 메서드 블록 코드이며, method 라는 이름과 정수형 배열 parameter가 시그니쳐이다. namespace는 sample.package.Class 이며, 라이프 타임은 Class 의 인스턴스가 생성되고 소멸되는 동안이다.
[ parameters , { ?, ( int[] ), ( sample.package.Class.method() ), ( method's Lifetime ) } ]
매개변수 parameters 는 메서드 호출시에 값이 결정되고, int 타입의 배열이며, namespace(scope)는 sample.package.Class.method 이다. method 가 호출되고 종료됨에 따라 라이프타임이 결정된다.
[ a , { 4, ( int ), ( sample.package.Class.method() ), ( method's Lifetime ) } ]
변수 a 는 4를 값으로 가지고, int 타입이며, namespace(scope)는 parameters와 동일하게 sample.package.Class.method 이다. 라이프타임은 종료 시점은 method가 종료될 때 이지만, 시작은 parameters 와 달리 메서드 실행 중 변수 a 가 정의될 때 메모리에 할당된다.
// Block A
{ // Block A's frames
int x = 1; // (x, 1)
int y = 2; // {(x,1),(y, 2)}
int z = 3; // {(x,1),(y, 2),(z, 3)}
//Block B
{ // Block B's frames
int x = 2; // (x,2)
int y = 3; // {(x,2), (y,3)}
// Block A - [static link] - Block B
x + y + z;
/**
* x + y + z {(x,2), (y,3)}
* 2 + y + z {(y,3)}
* 2 + 3 + z {} - {(z, 3)}
* 2 + 3 + 3 {} - {(z, 3)}
* z 는 B 의 스코프 밖인 A 에 속해 있지만
* B 의 frame 에는 존재하지 않지만 액세스가 가능한 상태
*/
}
}
블록은 일반적으로 생각하는 코드 블록(중괄호 {} 로 둘러싸인 것)을 이야기한다. 그리고 블록 내에서 정의(definition) 되는 변수들은 (key, value) 형태의 Dictionary 로 저장된다. 또한 블럭은 각각의 블럭마다 frame 을 가지는데, Dictionary 와 frame 은 거의 유사하지만 Dictionary 는 데이터의 관리, frame 은 변수의 범위와 수명 관리에 사용되는 등 약간의 차이가 있다.
Block A (이하 A) 는 Block B(이하 B)를 감싸고 있는 형태이다. 주석을 좀 더 구체적으로 설명하자면 다음과 같다.
A 는 코드가 진행됨에 따라 x, y, z 라는 이름을 가진 변수가 정의되며 이것은 (key, value) 형태의 Dictionary 로 정리된다. 그리고 A 의 frame 은 {(x,1),(y, 2),(z, 3)} 이다.
Block B 에 진입하게 되면 A 와는 별개의 frame 가진다. 따라서 코드가 진행됨에 따라 B의 frame 은 {(x,2), (y,3)} 로 구성되는데, 블록마다 별개의 frame 를 갖지만 실제로 B 에서는 A 의 frame 에 있는 값을 사용할 수 있다. 그래서 논리적으로 A 의 frame 와 B의 frame 는 연결되어있다고 할 수 있다. 그래서 x + y + z 를 연산할 때, x 와 y 는 B 자신의 frame에서 찾지만 z 는 A 의 frame 에서 찾는다.
Namespace 파트를 정리하다가 signature 부분에서 깨달은 부분이 있었는데, Java 에서 클래스에 메서드를 정의할 때, 같은 이름의 메서드에 대해 parameter 를 다르게 하여 Method Overload 를 할 수 있는데, 어째서 return 타입에 대해서는 Overload 가 불가능한지 알 수 있었다. 메서드의 signature는 메서드의 name 과 parameter 뿐이고 return 타입에 대해서는 관리가 되지 않아 논리적으로 다르다고 할 수 없기 때문이다.
글 잘 봤습니다, 많은 도움이 되었습니다.