sitelink1  
sitelink2  
sitelink3  
sitelink4  
sitelink5  
sitelink6  
http://sdnkorea.com/blog/216

J2SE 5.0가 출시되면서 새로운 기능들이 많이 소개되었다. static imports는 글로벌 컨스턴트를 생성하고 활용하는 데 도움이 되며, 사용자의 코드에 사용할 수 있는 가장 쉬운 기능 중의 하나라고 할 수 있다. 이번 테크팁에서는 컨스턴트와 메서드에 static imports를 사용해보도록 한다. "컨스턴트 인터페이스"를 사용하는 기존의 테크닉부터 얘기 하자면, 이 인터페이스들은 단지 컨스턴트를 갖고 있기 위해서만 존재하며, 이 컨스턴트들은 유틸리티 클래스 안으로 이동시켜야 하지만 이 클래스들을 사용하기 힘들었다. static imports에는 이런 문제가 없다. static imports는 컨스턴트에 사용됨과 더불어 메서드와 클래스의 호출을 용이하게 만들어 준다. 그러나 이런 식으로 static imports를 사용하면 사용자의 코드를 읽기 어렵게 만든다는 단점이 있으며, 이는 와일드 카드의 경우에 특히 그러하다. 메서드와 속성들이 어디에서 생성되는지 측정하기 힘들게 된다.

과거에는 개발자들이 글로벌 컨스턴트로 취급될 값을 저장하기 위해 인터페이스를 사용하는 것이 보편적이었다. 다음은 그 예이다.

   public interface BadIrrationalConstants {
     public static final double SQRT_TWO = 1.414;
     public static final double SQRT_THREE = 1.732;
   }

특히 한 개 이상 그룹의 컨스턴트를 필요로 했던 개발자들이 이렇게 하곤 했다. 예를 들어 어떤 개발자는 BadIrrationalConstants 인터페이스에서 정의된 값들과 같이 BadIrrationalConstants 인터페이스에서 정의된 값들이 필요했을 것이다. 다음은 BadTranscendentalConstants 인터페이스이다.

 public interface BadTranscendentalConstants {
     public static final double PI = 3.14159;
     public static final double E = 2.71828;
   }

글로벌 컨스턴트를 사용 가능하게 만들기 쉽기 때문에 컨스턴트 인터페이스 테크닉을 사용하는 것은 흥미롭다. 다음과 같이 필요 컨스턴트를 포함하는 각 인터페이스를 간단하게 구현해볼 수 있다.

   public class BadUseOfConstants implements
     BadTranscendentalConstants, BadIrrationalConstants {

    public static double sinPiOverFour() {
       return SQRT_TWO / 2;
     }

     public static void main(String[] args) {
       System.out.println("Pi is approximately " + PI);
       System.out.println("The sin of Pi/4 is about " +
         sinPiOverFour());
     }
   }

J2SE 5.0이 출시되기 이전 유일한 대체방법은 BadIrrationalConstants.SQRT_TWO 같은 fully qualified names를 모든 곳에 사용하는 것이었으나, 이는 지나치게 장황하고BadUseOfConstants 같은 오류를 야기시켰다.

위와 같은 방법의 문제는 컨스턴트들이 이제 타입 BadUseOfConstants의 일부라는 것이다. 이 컨스턴트들을 이용하는 어느 클래스나 퍼블릭 인터페이스에 이들을 추가한다. 이것은 클래스 추가적인 수정에 제약이 된다. 클래스의 클라이언트가 현재 있는 컨스턴트들에 의존하려하기 때문이다. 대신에 컨스턴트들은 다음과 같이 반드시 클래스의 일부가 되어야한다.

   package staticEx;

   public class IrrationalConstants {
     public static final double SQRT_TWO = 1.414;
     public static final double SQRT_THREE = 1.732;
   }

SQRT_TWO and SQRT_THREE 를 사용하기 위해 IrrationalConstants를 확장하기 전에 TranscendentalConstants에 정의된 컨스턴트 또한 필요하다고 가정하자.

   package staticEx;

   public class TranscendentalConstants {
     public static final double PI = 3.14159;
     public static final double E = 2.71828;
   }

J2SE 5.0 출시 이전에는 이 컨스턴트들을 사용하는 것이 꽤나 힘이 들었다. 때로는 컨스턴트들이 사용된 방식도 분명치 않았다. 그러나 static import는 사용자의 코드에 정적 구성요소를 쉽게 임포트할 수 있게 한다. 예를 들어 정적 클래스 속성인 SQRT_TWO를 사용하고자 한다면 컨스턴트를 사용하고자 하는 클래스의 첫부분에 다음과 같이 선언하면 된다.

   import static staticEx.IrrationalConstants.SQRT_TWO

그러면 BadTranscendentalConstants 에서와 같이 SQRT_TWO를 이용할 수 있다. static 키워드를 keyword 임포트 후에 사용해야 함을 잊지 말기 바란다. static 키워드 없이 다음을 실행하면 컴파일되지 않을 것이다. J2SE 5.0 컴파일러를 이용하여 아래의 클래스 ConstantsWithStaticImport를 컴파일하고 구동하자.

   package staticEx;

   import static staticEx.IrrationalConstants.SQRT_TWO;
   import static staticEx.IrrationalConstants.SQRT_THREE;
   import static staticEx.TranscendentalConstants.PI;

   public class ConstantsWithStaticImport {

     public static double sinPiOverFour() {
       return SQRT_TWO / 2;
     }

     public static void main(String[] args) {
       System.out.println("Pi is approximately " + PI);
       System.out.println("The sin of Pi/4 is about " +
         sinPiOverFour());
     }
   }

다음과 같이 표시될 것이다.

   Pi is approximately 3.14159
   The sin of Pi/4 is about 0.707

와일드카드를 임포트 할 때 사용할 수 있다. 이 경우에 처음의 두개의 정적 스테이트먼트를 다음과 같이 교체할 수 있다.

   import static staticEx.IrrationalConstants.*;

언제나 그렇듯이, 와일드카드를 사용하지 않으며 구체적이어야 어떤 것이 임포트되는 지 정확하게 제어할 수 있으며, 소스 코드를 읽는 다른 사람이 정확히 이해할 수 있다.

static imports를 정적 속성에서 뿐 아니라 정적 메서드에서도 사용할 수 있는데 아래의 클래스 IrrationalConstants2에서는 이 두 가지가 모두 나와있다.

   package staticEx;

   public class IrrationalConstants2 {
     public static final double SQRT_TWO = 1.414;
     public static final double SQRT_THREE = 1.732;

     public static double sinPiOverFour() {
       return SQRT_TWO / 2;
     }
   }

와일드카드를 사용하며 모두 사용 가능하게 만들어보자. 정적 메서드인 sinPiOverFour()를 호출할 수 있으며 이는 IrrationalConstants2 에서 다음과 같이 정의된다.

   package staticEx;

   import static staticEx.IrrationalConstants2.*;
   import static staticEx.TranscendentalConstants.*;

   public class ConstantsWithStaticImport2 {

     public static void main(String[] args) {
       System.out.println("Pi is approximately " + PI);
       System.out.println("The sin of Pi/4 is about " +
         sinPiOverFour());
     }
   }

그러나 벌써 읽기에 문제가 생겼음을 알 수 있을 것이다. sinPiOverFour()이 IrrationalConstants2 클래스와 TranscendentalConstants클래스 중 어디에 있는 지 결정하기 힘든데, 이는 임포트 안의 와일트카드를 호출되는 메서드에 대한 explict reference로 대체함으로 명확히 할 수 있다. java.lang.Math와 같은 표준 J2SE의 클래스를 사용하여 혼동을 줄일 수 있다. static import을 이용하면 PI와 sin()에 대한 Math.PI와 Math.sin() 같은 클라이언트 코드를 줄일 수 있다.

   package staticEx;

   import static java.lang.Math.*;

   public class ConstantsWithStaticImport3 {

     public static void main(String[] args) {
       System.out.println("Pi is approximately " + PI);
       System.out.println("The sin of Pi/4 is about " +
         sin(PI / 4));
     }
   }

정적 메서드, 정적 속성과 더불어 정적 클래스를 위해 static import 를 사용할 수 있다. 예를 들어 java.awt.geom.Point2D.Double 클래스는 java.awt.geom.Point2D의 정적 하위 클래스이다. java.awt.geom.Point2D.Double를 임포트하면 Double.xxx를 사용하여 그 클래스의 모든 정적 구성 요소를 참조할 수 있게 된다. 다음의 예제 StaticClassEx 에서는 System.out.println() 호출을 간단하게 만들기 위해 마지막 클래스인 java.lang.System의 정적 필드 out를 사용하였다. StaticClassEx는 out.println()를 사용하여 standard를 출력하고 Double.distance()를 사용하여 정적 method distance()를 호출한다.

   package staticEx;

   import static java.awt.geom.Point2D.Double;
   import static java.lang.System.out;

   public class StaticClassEx {

     public static void main(String[] args) {
       out.println("The diagonal of a unit square is " +
         Double.distance(0.0, 0.0, 1.0, 1.0) + ".");
     }
   }

다음은 그 결과이다.

   The diagonal of a unit square is 1.4142135623730951.

적절하게 사용되었을 때 static imports는 사용자의 코드를 읽기 간단하면서도 정적 변수, 메서드, 클래스들과 호환되기 쉽게 만들 수 있다. 이 테크닉을 남용하기 않길 바라며, 모호한 표현의 가능성이 있을 때 변수나 메서드를 명확하게 임포트하길 바란다.

static imports에 대해 좀 더 자세히 알고 싶으면 J2SE 5.0의 새로운 기능 중 Static Import 섹션을 읽어보길 바란다.


번호 제목 글쓴이 날짜 조회 수
123 상속과 연관(association, composition) 황제낙엽 2008.04.10 436
122 HttpServletRequest 객체의 함수 모음 file 황제낙엽 2008.01.28 582
121 ObjectCache클래스 와 Server/Client프로그램 file 황제낙엽 2007.11.07 490
120 ObjectCache시스템의 구현을 위한 추가 고려사항 황제낙엽 2007.11.04 459
119 문제 : 간단한 ObjectCache 프로그램을 구현하라 황제낙엽 2007.11.01 558
118 ObjectCache 클래스를 구현한 예제 소스 파일들 황제낙엽 2007.11.01 432
117 LinkedHashMap 를 이용한 LRU 캐쉬 구현 황제낙엽 2007.11.03 766
116 J2SE 5.0 에서의 QUEUE와 DELAYED 프로세싱 황제낙엽 2007.11.02 449
115 J2EE object-caching frameworks (ObjectCache) 황제낙엽 2007.11.02 1852
114 Object Caching in a Web Portal Application Using JCS (ObjectCache) 황제낙엽 2007.11.02 490
113 Java Object Cache | Patterns 'N J2EE (ObjectCache) 황제낙엽 2007.11.01 530
112 Runtime 클래스를 이용한 JVM 메모리 사용량 확인 황제낙엽 2007.11.05 470
111 자바 애플리케이션에서 동적으로 PDF 파일 생성하기 황제낙엽 2007.10.03 391
110 싱글사인온(single sign-on)으로 엔터프라이즈 자바 인증을 단순하게! 황제낙엽 2007.10.03 444
109 [BPP] 게시판 페이징 로직 분석 - M1.3 file 황제낙엽 2007.09.26 294
108 [HttpURLConnection] 2초후에 연결 끊어주는 URLConnection 예제 황제낙엽 2007.09.08 481
107 Assertions : 비교 확인, 조건 확인, Null 확인 황제낙엽 2007.09.02 418
106 [BPP] 게시판 페이징 로직 분석 - M1.2 - SQLMap(ibatis) 지원 file 황제낙엽 2007.08.29 338
» J2SE 5.0 - 컨스턴트와 메서드에 static imports 사용하기 황제낙엽 2007.08.28 469
104 J2SE 5.0 - 향상된 루프문 황제낙엽 2007.08.27 447