2010년 11월 29일 월요일
animated gif for mildet
2010년 11월 25일 목요일
2010년 11월 21일 일요일
FireBug
listener model
Listeners
A listener is called when the user does something to the user interface that causes an event. Altho these events usually come from the user interface, they can have other sources (eg, a Timer).
Button listener example
After a button is created, you will add a listener to it. Eg,
b.addActionListener(listener_object);
When the button is clicked, a call is made to the actionPerformed()
method defined in the class of the listener object. An ActionEvent object is passed as a parameter to it actionPerformed()
.
The listener method must be called actionPerformed
There is (unfortunately) no way to use any given method as a listener -- the listener must be called actionPerformed
.
One per class. Because there can only be one actionPerformed
method in a class, a new class is needed for every separate listener, or you have to share an actionPerformed
method and use the ugly technique of figuring out who caused the call.
Incidental note. To address this awkward situation C# has delegates, which allow any method to be a listener, provided it has the correct return type and parameters. This doesn't provide any additional functionality, but it is more convenient.
You need to create an instance of the class which defines the actionPerformed
method for the button, and it is this instance that becomes the button listener.
Common Listener Strategies
Here are common ways to write listeners:
- Named Inner Class Listeners are one of the most common ways to write small programs. They are convenient to write and and be shared with several components.
- Anonymous Inner Class Listeners are sometimes used to associate a different listener with each button or other control. This is a little quicker to write, but lacks some of the flexibility of inner class listeners.
- Top-level Listeners (this) are commonly used where there is only one source of an event. For example, if you are defining a subclass of JPanel to use for drawing with a mouse, an instance of this new class will typically also be the mouse event listener. Similarly with a JPanel used for animation -- the panel itself may serve as the ActionListener for the Timer. Do not use "this" as a listener for buttons, menus, etc. because all controls must then share that one action listener.
- Action and AbstractAction objects are action listeners. In some ways they are more powerful than other action listener strategies in that they can easily be used to enable or disable multiple controls. An action object can be shared with many controls; eg, the same action is sometimes accomplished with a menu item and a button or toolbar tool. They encapsulate the name, description, enabled status, listener, and icon information. This is a good choice for large interfaces, and quite compatible with the MVC pattern (see below).
- External Listeners - To implement the Model-View-Controller pattern, all listeners will effectively be in the Controller module. There are a number of ways to split the controller actions from the View part of the interface. One example is in Model-View-Controller (MVC) Structure.
- Subclassing a component and overriding processActionEvent(). This peculiar scheme certainly isn't general, and I've never seen it done in a serious program. Do not do this.
The examples in these notes use named inner class listeners most often, anonymous inner class listeners in a few examples, and top-level listeners for mouse listeners for graphics panels.
Other Resources
2010년 11월 20일 토요일
JSON in AJAX
Syntax of JSON. Decoding and encoding json in php and javascript. Simple exam...
2010년 11월 19일 금요일
2010년 11월 13일 토요일
2010년 11월 12일 금요일
2010년 11월 9일 화요일
Item 8. equals를 재정의 할 떄는 일반적인 계약을 따르라.
Item 8. equals를 재정의 할 떄는 일반적인 계약을 따르라.
Posted on : 29-10-2008 | By : 기선 | In : Java
Tags: Effective Java, Equals, Item 8
3
equals 메소드 재정의은 간단해 보이지만 잘못 될 여지가 많다.
equals 메소드 재정의가 필요 없는 경우
- 클래스 특성상 각각의 객체가 유일할 때. ex) Thread
- “논리적인 일치” 확인 기능을 제공하는지 관심 없을 때. ex) Random
- 이미 상위 클래스에서 재정의한 equals를 재공하며, 그 로직이 현재 클래스서도 적당할 때. ex) AbstractSet, AbstractList, AbstractMap
- 클래스가 private 또는 package-private인 경우 equals가 절대로 호출되지 않을거라는 확신이 있을 때.
equals 메소드 재정의가 필요한 경우
- logical equality 개념이 있는 클래스
- 보통 value class(예외, 싱글톤, Enum 타입 – Object의 equals가 곧 logical equality)
- ex) Integer, Date
equals를 재정의할 때 따라야 하는 일반적인 계약(JavaSE6 Object 스펙)
- Reflexive: null이 아닌 레퍼런스 값 x에 대해, x.equals(x)는 반드시 true를 반환해야 한다.
- Symmetric: null이 아닌 레퍼런스 값 x와 y에 대해, y.equals(x)가 true를 반환 경우에 한 해서만 x.equals(y)도 true를 반환해야 한다.
- Transitive: null이 아닌 레퍼런스 값 x, y, z에 대해, x.equals(y)가 true고 y.equals(z)가 true면 x.equals(z)도 반드시 true여야 한다.
- Consistent: null이 나닌 레퍼런스 값 x와 y에 대해, x.equals(y)를 몇 번 호출하든지 계속해서 일관적으로 true를 반환하거나 false를 반환해야 한다.
- null이 아닌 레퍼런스 값 x에 대해, x.equals(null)은 반드시 false를 반환한다
규칙을 어기면 다른 객체가 어떻게 동작할지 예측하기 힘들다.
고품질 equals 메소드 레서피
- 같은 객체를 참조하는 레퍼런스가 아닌지 확인. == 사용.
- 정당한 타입인지 확인할 떄는 instanceof 연산자를 사용,
- 적당한 타입으로 캐스팅
- 각각의 필드가 같은지 확인. primitive 타입은 == 사용, 레퍼런스 타입은 equals 사용
- 메소드 작성을 마친 뒤에, symmetric, transitive, comsistent 한지 단위 테스트를 작성한다.
example
if (o == this)
return true;
if (!(o instanceof PhoneNumber))
return false;
PhoneNumber pn = (PhoneNumber)o;
return pn.lineNumber == lineNumber
&& pn.prefix == prefix
&& pn.areaCode == areaCode;
}
the number of ones in the number
/*
* The statement inside the loop clears the
* least significant bit of the number.
*
* The loop terminates when all bits are zero.
*
* Therefore, the number of ones in the number
* is simply equal to the number of times the
*program goes through the loop.
*/
unsigned number_of_ones(unsigned x)
{
unsigned count;
for (count = 0; x != 0; count++) {
x &= x - 1;
}
return count;
}
데드락피하기
학부 OS 과목에서 데드락에 대해 배웠을 것이다. 데드락이 발생하기 위한 4가지 조건, 데드락 감지하기, 데드락 피하기 등 꽤 많은 내용이 있다. 그런데 C++로 멀티스레드 게임 서버를 짤 때는 그런 지식들은 별 쓸모가 없고, 딱 한가지 조건만 철저하게 지키면 된다:
간단하다. 데드락 문제를 다 해결했다! 야 신난다!
아니다. 사실, 간단하지 않다. 프로그램이 좀 커지면 이 조건을 깨뜨리기가 무척 쉬워지고, 깨뜨린 사실을 발견하기는 무척 어려워진다. 예를 들어 보겠다. 어떤 함수 Ouch()가 있는데 그 함수는 안에서 락 a를 잡는다고 치자. 그런데 프로그램 전체에서 락을 a b c 순서로 잡기로 했다. 그러면, 락 b 혹은 c를 잡은 상태에서 Ouch()를 호출하면 데드락이 일어날 수 있다. 만약 Ouch()가 직접 락을 잡는 것이 아니라 콜스택을 5단계쯤 타고 들어가서 호출된 전혀 다른 곳의 함수가 락 a를 잡더라도 마찬가지다.
어떤 함수를 호출하는 코드를 쓸 때, 현재 맥락에서 어떤 락을 잡은 상태인지, 호출할 함수와 그것이 간접적으로 호출할 모든 함수들이 어떤 락을 잡을지를 일일이 확인해야 한다. 게다가 코드에 변경이 일어날 때마다 영향받는 호출 경로를 모두 확인해야 한다. 사람이 직접 하기에는 너무 힘든 일이다. 간단한 줄 알았던 문제가 프로그램의 규모 때문에 어려운 문제가 된다.
우리네 소프트웨어 세계는 모듈의 인터페이스를 알고 그대로 따르면, 세부 구현에 신경쓰지 않아도 행복하게 살 수 있다는 가정에 기반해서 모듈화의 성을 쌓아올렸다. 그러나 락 기반 멀티스레드 환경에서는 함수를 호출할 때 그 호출경로에서 잡힐 락에 대해 신경써야 한다. 곧 함수가 어떤 락을 잡을까 하는 것이 (어떤 예외를 던질까처럼) 함수의 인터페이스의 일부가 된다. 하지만 지금 널리 쓰이고 있는 언어들은 함수의 락잡기를 명시적으로 표기하도록 하지 않는다. 헤더에 기록된 인터페이스만 보고는 프로그래밍할 수 없는 것이다.
그러나 맥주가 미지근하면 얼음을 넣어 마시면 되듯이, 컴파일러가 검사해 주지 않으면 실행시간에 확인하면 된다. 개별 스레드가 잡고 있는 락을 모두 기록하고, 새로이 락을 잡으려 할 때 기존에 잡은 락 목록을 확인해서 순서 규칙을 깨뜨리지 않는지 assert() 하는 것이다. assert()에 걸리면 디버거로 들어가든지 즉시 덤프를 남기도록 해서, 어떤 호출 경로에서 데드락이 생기는지 분석하면 된다.
- # TLS 타입의 객체는 포인터 한 개 크기의 스레드별 저장 공간을 제공한다.
- # TLS 객체를 담고 있는 lockhistory 전역변수가 선언되어 있다.
- # 락 객체에는 enter(), leave() 멤버 함수와 type 필드가 있다. type 필드는 락의 순서를 나타내며, type이 작은 것부터 큰 것 순서로 잡도록 규칙을 정했다.
- # 전처리기를 적절히 써서 서비스용 빌드에서는 데드락 검사 코드를 빼 버릴 수 있도록 하자.
- # 스레드를 시작할 때:
- lockhistory := create new set
- # 락 lock에 진입하려 할 때:
- for( oldlocktype in lockhistory ):
- assert( oldlocktype <= lock.type )
- lockhistory.insert( lock.type )
- lock.enter()
- # 락 lock에서 탈출하려 할 때:
- lock.leave()
- assert( lockhistory.has( lock.type ) )
- lockhistory.erase( lock.type )
이 방법은 프로그램의 호출 경로가 대체로 변하지 않는다는 가정을 전제로 하고 있다. 만약 테스트에서 한번도 수행되지 않았던 경로로 프로그램이 작동할 수 있다면, 테스트 환경에서 한번도 락 순서를 위반하지 않았더라도 서비스에서 데드락이 발생할 수 있으니 백 퍼센트 안심할 수는 없다. 그러나 그런 경우는 단순 실수보다는 설계 문제에 가까우므로 미리 파악할 수 있을 것이다.
동영상 응답