검색결과 리스트
글
[Java] Error 혹은 Debug시 등장하는 method인 access$000
안드로이드 프레임워크를 공부하면서 종종 신기한 경우들을 마주치곤 합니다. 그 중 하나가 바로 실제 코드상에는 존재하지 않던 method가 디버깅을 할 때 예상치 못하게 등장하기 때문입니다.
분명 소스코드 상에서는 존재 자체가 없었던 method인 'access$000'가 이렇게 디버깅을 하던 도중 발견되는 경우가 종종 있습니다. 과연 이것의 정체는 무엇일까요?
이 문제의 원인은 바로 Java 언어의 특징 중 하나인 Inner class에서 원인을 찾을 수 있습니다.
Java를 공부하신 분들이라면 누구나 아시는 듯이 Inner class는 말 그대로 Class 안에 내포된 Class를 의미합니다. C언어에서 마치 Struct 구조체 안에 또다른 Struct를 품은 듯한 형태를 띄고 있는 구조라고 이해하시면 되겠습니다.
아래는 Inner class가 구현되어 있는 예제입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class Test { public void func() { System.out.println(new Inner().a); System.out.println(new Inner().getInt()); System.out.println(new Inner2().b); System.out.println(new Inner2().getInt()); } class Inner { private int a; public int getInt() { return a; } } class Inner2 { int b; public int getInt() { return b; } } } | cs |
위의 예제는 Test 클래스 안에 두 개의 Inner class로 구성되어 있는 소스코드입니다. Test 클래스의 입장에서 Inner class는 private 인 경우에도 접근이 가능하여 위의 func() method에서 실행되는 모든 함수들이 제 기능을 하는 것을 확인하실 수 있습니다.
그런데 여기서 문제가 발생하게 됩니다. Java의 소스코드를 컴파일한 결과물인 bytecode는 Inner class를 고려하지 않는다는 점입니다. 이로 인해 bytecode 상에서 func() method는 접근할수 없는 field 값은 Inner 클래스의 a의 값에 접근할 수 없게 됩니다.
그렇기 때문에 실제 bytecode 상에서는 private로 설정된 내부클래스에 접근할 수 있도록 하기 위해 소스코드를 살짝 바꾸어서 기능을 똑같이 구현되게 하는데 실제 위의 설계된 소스코드를 디컴파일하게 되면 위에서 보았던 메소드인 access$000이 등장하는 것을 알 수 있습니다.
아래의 예제는 Inner class가 적용되었을 경우를 가장한 예제입니다. 위의 소스코드와 비교하시면 자신이 설계한 소스코드에서 등장하는 access$000이 어느 시점에서 등장하게 되는지 어느 정도 감이 오실 것이라 생각됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | public class Test { public void func() { System.out.println(Test$Inner.access$000(new Test$Inner(this))); System.out.println(new Test$Inner(this).getInt()); System.out.println(new Test$Inner2(this).b); System.out.println(new Test$Inner2(this).getInt()); } } class Test$Inner { final Test this$0; private int a; Test$Inner(Test test) { this$0 = test; } public int getInt() { return a; } static int access$000(Test$Inner inner) { return inner.a; } } class Test$Inner2 { final Test this$0; int b; Test$Inner2(Test test) { this$0 = test; } public int getInt() { return b; } } | cs |
아래는 제가 안드로이드 프레임워크를 분석하던 도중 access$000가 뜨던 부분입니다. 보시는 대로 new Handler() 방식으로 내부클래스를 구성하고 있으며 이를 access$000 함수명을 통하여 updateWindow() 함수에 접근하고 있는 것을 확인할 수 있습니다.
/frameworks/base/core/java/android/view/SurfaceView.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public class SurfaceView extends View { .... final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case KEEP_SCREEN_ON_MSG: { setKeepScreenOn(msg.arg1 != 0); } break; case GET_NEW_SURFACE_MSG: { handleGetNewSurface(); } break; case UPDATE_WINDOW_MSG: { updateWindow(false, false); } break; } } }; .... } | cs |
출저 : http://www.javacodegeeks.com/2012/05/java-pitfalls-field-access-in-inner.html
'프로그래밍 팁' 카테고리의 다른 글
[C/C++]thread 조건변수 다루기 - pthread_cond_broadcast() (0) | 2015.09.01 |
---|---|
[JAVA]JDWP(Java™ Debug Wire Protocol) (0) | 2015.08.21 |
[C/C++] typedef 함수 포인터 구현원리 (2) | 2015.04.06 |
[JAVA]윈도 CMD를 통해 자바 Command Line 명령어 활용하기 (0) | 2014.10.04 |
[JAVA] 간단한 파일 입출력(FILE I/O) 구현 (0) | 2014.09.10 |