java - jar

Development/Java 2012. 11. 9. 00:03


여러개의 파일을 하나로 모아 압축한 것을 아카이브(ARchive) 라고 한다.
JAR 는 복수의 클래스 파일과 그 밖의 파일을 하나로 모아 압축한 파일 형식이다.
파일들을 모아 압축을 통해 용량을 줄일 수 있기 때문에 데이터를 교환하기에 편리하다.

일반적으로 자바 프로그래밍을 하다보면 jar 파일을 심심찮게 볼 수 있는데,
압축파일이기 때문에 알집 같은 압축,해제 프로그램으로 풀 수 있다.
즉, 다른 의미로 해석하자면, 굳이 jar 커맨드를 이용하지 않아도, 일반 압축 프로그램에서
jar 파일을 생성할 수 있다는 의미이다.
알집의 경우, 압축은 가능한데, 압축을 해제하기 전에 미리보기 하는 기능은 되지 않았다.


jar 압축풀기

jar xvf 파일명.jar ./경로

 

jar 파일압축

jar cvf 파일명.jar ./경로

 

○ JAR 커맨드(명령)
JAR 파일은 명령 프롬프트에서 jar 커맨드(명령)를 사용하여 만들어 낼 수 있다.
jar 커맨드는 'jar' 뒤에 다음과 같은 옵션을 붙여서 사용한다.

옵션 : 설명
c : 새 아카이브를 만든다.
t : 아카이브의 내용을 표시한다.  //일반적으로 내용을 볼때는 t 옵션만 사용하지 않고, tf 옵션으로 한다.
x : 아카이브에서 파일을 추출한다.
u : 기존의 아카이브를 업데이트 한다.
v : 명령 프롬프트에상세정보를 표시한다.
f : 아카이브 파일 이름을 지정한다.
m : manifest 정보를 포함시킨다.
o : 저장만 수행하며 ZIP 압축을 사용하지 않는다.
M : manifest 파일을 만들지 않는다.
i : 지정된 jar 파일에 대한 색인 정보를 생성한다.
C : 지정된 디렉토리로 변경하고, 다음 파일을 포함시킨다.


jar 옵션에 대한 사용법을 다시 살펴보면
--------------------------------------------------
사용법: jar {ctxu}[vfm0Mi] [jar-file] [manifest-file] [-C dir] files ...
옵션:
  -c  새 아카이브를 만듭니다.
  -t  아카이브에 대한 목차를 나열합니다.
  -x  아카이브에서 명명된 (또는 모든) 파일을 추출합니다.
  -u  기존의 아카이브를 업데이트합니다.
  -v  표준 출력에 대한 자세한 정보 출력을 생성합니다.
  -f  아카이브 파일 이름을 지정합니다.
  -m  지정된 manifest 파일에서 manifest 정보를 포함시킵니다.
  -0  저장만 수행하며 ZIP 압축을 사용하지 않습니다.
  -M  입력 항목에 대한 manifest 파일을 만들지 않습니다.
  -i  지정된 jar 파일에 대한 색인 정보를 생성합니다.
  -C  지정된 디렉토리로 변경하고 다음 파일을 포함시킵니다.
디렉토리인 파일이 하나ㅏ도 있으면 재귀적으로 처리됩니다.
'm' 및 'f' 플래그가 지정된 순서대로 manifest 파일 이름과 아카이브 파일 이름을 지정해야 합니다.

예 1: classes.jar 라는 아카이브 파일에 두 클래스 파일을 아카이브하려면
   jar cvf classes.jar Foo.class Bar.class
dP 2: 기존의 manifest 파일 'mymanifest' 를 사용하고 foo/ 디렉토리에 있는
   모든 파일을 'classes.jar' 로 아카이브합니다.
   jar cvfm classes.jar mymanifest -C foo/ .
--------------------------------------------------

책에서는 o 옵션이 애매하게 표시되어 있는데,
명령 프롬프트 상에서 설명해주는 명령어는 영어 o 소문자가 아니라 숫자 0 이다.


간단한 작업을 할때는 한가지 옵션만을 사용하겠지만,
복잡한 명령을 수행할때는 명령 옵션을 조합해서 사용하는데,
만약, 파일 A.class, B.class 두개의 파일을 신규 작성한 AB.jar 에 저장하려 한다면,

>jar cf AB.jar A.class B.class

라고 한다.
cf 옵션이 두개의 옵션을 조합해서 사용하는 명령인데,
새로 만드는 옵션인 c 와 지정한 파일명을 사용하는 f 를 조합한 것이다.
그래서, AB.jar 라는 지정된 파일명으로 새로 만들고, 그 안에 A.class 와 B.class 두개를 포함시키는 것이다.
JAR 파일에 들어갈 파일명은 공백으로 구분해준다.

만약, JAR 파일 AB.jar 에 저장되어 있는 파일의 내용을 표시하려면,

>jar tf AB.jar

라고 한다.
여기서 t 옵션은 내용을 표시하도록 하는 옵션이고, f 옵션은 지정된 파일명을 의미한다.
이 옵션을 이용하면, 윈도우 탐색기에서 폴더트리를 보여주듯이,
jar 파일안에 어떠한 파일들이 들어있는지 경로와 파일명들을 보여준다.


○ 매니페스트(manifest) 파일
매니페스트 파일은 JAR 파일에 들어 있는 파일의 정보를 기술한 파일이다.
매니페스트 파일을 지정하지 않고 아카이브를 생성하게 되면, 표준 매니페스트 파일이 포함된다.
아래와 같은 내용의 매니페스트 파일을 작성하고, JAR 파일에 포함시켜두면, JAR 파일을 직접 실행할 수 가 있다.

main-class: A

실행하고 싶은 클래스명을 적어주는 것이다.
클래스명을 적을때는, 클래스명 앞에서는 스페이스가 반드시 있어야 하며,
뒤에는 개행문자가 필요하다.


○ JAR 파일의 실행
압축을 해제하지 않은 상태에서 바로 실행할 수 있는 JAR 파일을 작성하려면 다음과 같이 기술한다.

(Hello.java)----------------------
class Hello{
  void hello(){
    System.out.println("Hello");
  }
}
----------------------------------

(Bye.java)------------------------
class Bye{
  void bye(){
    System.out.println("Bye");
  }
}
----------------------------------

(a.java)--------------------------
class a{
  public static void main(String [] args){
    Hello h = new Hello();
    Bye b = new Bye();
    h.hello();
    b.bye();
  }
}
----------------------------------

이렇게 소스를 작성한뒤 컴파일을 한다.
실행할 클래스명을 기술한 manifest.txt 라는 이름의 매니페스트 파일을 만든다.

Main-class: a

그런다음, JAR 파일에 매니페스트 파일을 포함하여 클래스 파일을 저장한다.

>jar cfm G.jar manifest.txt Hello.class Bye.class a.class

여기서, cfm 옵션은 지정한 파일이름(f)으로 새로 생성(c)하면서 매니페스트 파일을 포함(m)하는 것이다.

Jar 파일을 실행할때는 -jar 을 이용하는데, 아래와 같이 기술하면 된다.

-------------------
>java -jar G.jar
Hello
Bye
-------------------

즉, jar 파일로 압축하면서 매니페스트파일에 어떤 클래스를 시작클래스로 할것인지 지정하였기 때문에,
a.class 가 시작되며, a.class 에서는 마치 패키지에서 다른 클래스들을 포함시켜서 사용하듯이,
Hello.class 와 Bye.class 의 클래스들을 불러와써 쓸 수 있는 것이다.


출처 - http://fendee.egloos.com/9023202






JAR에 대해 모르고 있던 5가지 사항

클래스 번들 이상의 Java Archive

Ted Neward, Principal, Neward & Associates


요약:  많은 Java™ 개발자들이 JAR의 기본 기능만을 사용하고 있습니다. 단순히 JAR을 사용하여 클래스를 번들로 묶어서 프로덕션 서버로 전달하고 있을 뿐입니다. 하지만 JAR은 단순히 이름이 바뀐 ZIP 파일에 그치지 않고 그 이상의 기능을 제공합니다. Spring 종속성 및 구성 파일을 jar로 작성하는 방법에 대한 팁을 비롯하여 Java Archive 파일을 최대한으로 활용하는 방법에 대해 살펴봅니다.


대부분의 Java 개발자에게 JAR 파일과 그 특별한 사촌인 WAR 및 EAR은 단순히 장기적인 Ant 또는 Maven 프로세스의 최종 결과에 불과하다. 일반적으로 JAR을 서버(또는 드물게 사용자의 시스템)의 올바른 위치에 복사한 다음 잊어버린다.

실제로 JAR은 소스 코드를 저장하는 것 이상의 작업을 수행할 수 있지만 사용자가 가능한 작업과 작업 요청 방법을 알아야 한다. 5가지 사항 시리즈의 이 기사에서 제공하는 팁에서는 Java Archive 파일(및 WAR와 EAR)을 특히, 배치 시간에 최대한으로 활용하는 방법에 대해 설명한다.

많은 Java 개발자가 Spring을 사용하고 있고 Spring 프레임워크에서 일반적인 JAR 사용 방법이 문제가 되는 경우가 있기 때문에 일부 팁에서는 특별히 Spring 애플리케이션에서 JAR을 사용하는 방법에 대해 설명한다.

이 시리즈의 정보

Java 프로그래밍에 대해 알고 있다고 생각하는가? 하지만 실제로는 대부분의 개발자가 작업을 수행하기에 충분할 정도만 알고 있을 뿐 Java 플랫폼에 대해서는 자세히 알고 있지 않다. 이 시리즈에서 Ted Neward는 Java 플랫폼의 핵심 기능에 대한 자세한 설명을 통해 까다로운 프로그래밍 과제를 해결하는 데 도움이 되는 알려져 있지 않은 사실을 밝힌다.

먼저 이후 팁에서 기본적으로 사용할 표준 Java Archive 파일 프로시저를 보여 주는 간단한 예제를 살펴보자.

JAR로 저장하기

일반적으로 코드 소스를 컴파일한 후 jar 명령행 유틸리티 또는 더 일반적으로 Ant jar 태스크를 통해 Java 코드(패키지별로 구분됨)를 단일 콜렉션으로 수집하여 JAR 파일을 빌드한다. 이 프로세스는 매우 간단하기 때문에 여기에서는 다루지 않겠지만 이 기사의 뒷부분에서 JAR의 생성 방법에 대한 주제를 다시 살펴볼 것이다. 지금은 단지 메시지를 콘솔에 인쇄하는 매우 유용한 태스크를 수행하는 독립형 콘솔 유틸리티인Hello를 아카이브해야 한다(Listing 1 참조).


Listing 1. 콘솔 유틸리티 아카이브하기
package com.tedneward.jars;

public class Hello
{
    public static void main(String[] args)
    {
        System.out.println("Howdy!");
    }
}

Hello 유틸리티는 거창하지는 않지만 코드를 실행하여 JAR 파일을 탐색하기에 유용한 골격이다.

1. JAR은 실행 파일이다.

.NET, C++ 등의 언어는 역사적으로 OS 친화적인 장점을 가지고 있다. 즉, 명령행에서 단순히 해당 이름을 참조하거나(helloWorld.exe) GUI 쉘에서 해당 아이콘을 두 번 클릭하여 애플리케이션을 실행할 수 있다. 하지만 Java 프로그래밍에서는 실행 애플리케이션인 java가 JVM을 프로세스로 부트스트랩하고, 사용자가 실행할 main() 메소드가 있는 클래스를 나타내는 명령행 인수(com.tedneward.Hello)를 전달해야 한다.

이러한 추가 단계로 인해 Java에서는 사용자 친화적인 애플리케이션을 작성하기가 더 어렵다. 일반 사용자가 이러한 모든 요소를 명령행에 입력해야 한다. 하지만 이 작업은 많은 일반 사용자가 원하지 않는 것이다. 게다가 키보드를 잘못 눌러서 모호한 오류가 발생할 수도 있다.

이 문제를 해결하는 방법은 JAR 파일을 "실행 파일"로 만드는 것이다. 즉, Java 실행 프로그램이 JAR 파일을 실행할 때 시작할 클래스를 자동으로 인식할 수 있도록 만들면 된다. 이를 위해서는 다음과 같이 JAR 파일의 매니페스트(JAR의 META-INF 서브디렉토리에 있는MANIFEST.MF)에 항목을 추가하면 된다.


Listing 2. 시작점 알려주기
Main-Class: com.tedneward.jars.Hello

매니페스트는 이름/값 쌍으로 구성된 세트이다. 매니페스트에서는 캐리지 리턴과 공백으로 인해 문제가 발생할 수도 있기 때문에 JAR을 빌드할 때 Ant를 사용하여 매니페스트를 생성하는 방법이 가장 쉬운 방법이다. Listing 3에서는 Ant jar 태스크의 manifest 요소를 사용하여 매니페스트를 지정한다.


Listing 3. 시작점 빌드하기
    <target name="jar" depends="build">
        <jar destfile="outapp.jar" basedir="classes">
            <manifest>
                <attribute name="Main-Class" value="com.tedneward.jars.Hello" />
            </manifest>
        </jar>
    </target>

이제 사용자는 java -jar outapp.jar을 통해 명령행에서 파일 이름을 지정하는 것만으로도 JAR 파일을 실행할 수 있다. 일부 GUI 쉘에서는 JAR 파일을 두 번 클릭하여 실행할 수도 있다.

2. JAR은 종속성 정보를 포함할 수 있다.

Hello 유틸리티의 단어가 너무 많이 사용되고 있기 때문에 구현을 변경할 필요성이 제기되고 있다. Spring 또는 Guice와 같은 DI(Dependency Injection) 컨테이너가 많은 세부 사항을 자동으로 처리하기는 하지만 DI 컨테이너의 사용을 포함하도록 코드를 수정할 경우 Listing 4와 같은 결과가 발생할 수 있다는 문제점이 아직도 남아 있다.


Listing 4. Hello, Spring world!
package com.tedneward.jars;

import org.springframework.context.*;
import org.springframework.context.support.*;

public class Hello
{
    public static void main(String[] args)
    {
        ApplicationContext appContext =
            new FileSystemXmlApplicationContext("./app.xml");
        ISpeak speaker = (ISpeak) appContext.getBean("speaker");
        System.out.println(speaker.sayHello());
    }
}

Spring에 대한 추가 정보

이 팁에서는 독자가 종속성 주입 및 Spring 프레임워크에 익숙하다고 간주하고 있다. 두 주제에 대해 자세히 알고 싶으면 참고자료 섹션을 참조하기 바란다.

실행 프로그램에 대한 -jar 옵션은 -classpath 명령행 옵션의 내용을 겹쳐쓰기 때문에 이 코드를 실행할 때 Spring이 CLASSPATH  환경 변수에 있어야 한다. 다행스럽게도 JAR에서는 매니페스트에 표시할 다른 JAR 종속성을 선언할 수 있다. 이렇게 하면 사용자가 선언하지 않아도 CLASSPATH가 암묵적으로 작성된다(Listing 5 참조).


Listing 5. Hello, Spring CLASSPATH!
    <target name="jar" depends="build">
        <jar destfile="outapp.jar" basedir="classes">
            <manifest>
                <attribute name="Main-Class" value="com.tedneward.jars.Hello" />
                <attribute name="Class-Path" 
                    value="./lib/org.springframework.context-3.0.1.RELEASE-A.jar 
                      ./lib/org.springframework.core-3.0.1.RELEASE-A.jar 
                      ./lib/org.springframework.asm-3.0.1.RELEASE-A.jar 
                      ./lib/org.springframework.beans-3.0.1.RELEASE-A.jar 
                      ./lib/org.springframework.expression-3.0.1.RELEASE-A.jar 
                      ./lib/commons-logging-1.0.4.jar" />
            </manifest>
        </jar>
    </target>

Class-Path 속성에는 애플리케이션에서 사용하는 JAR 파일에 대한 상대 참조가 있다. 이 참조는 절대 참조로 작성하거나 접두부 없이 작성할 수 있으며, 이 경우 JAR 파일은 애플리케이션 JAR과 같은 디렉토리에 있는 것으로 간주된다.

아쉽게도 Ant Class-Path 속성에 대한 value 속성은 한 행으로 표시되어야 한다. 왜냐하면 JAR 매니페스트가 여러 Class-Path 속성을 처리하지 못하기 때문이다. 따라서 이러한 모든 종속성은 매니페스트 파일에 한 행으로 표시되어야 한다. 물론 보기에 좋지는 않지만java -jar outapp.jar을 사용할 수 있기에 그 가치는 충분하다고 할 것이다.

3. JAR은 암묵적으로 참조될 수 있다.

Spring 프레임워크를 사용하는 여러 다양한 명령행 유틸리티(또는 기타 애플리케이션)가 있다면 모든 유틸리티에서 참조할 수 있는 공통 위치에 Spring JAR 파일을 저장하여 효율을 높일 수 있다. 이렇게 하면 전체 파일 시스템 내에서 JAR 사본을 여러 개 유지하지 않아도 된다. Java 런타임에서 JAR에 대한 공통 위치로 사용하는 "확장 디렉토리"는 기본적으로 설치된 JRE 경로 아래의 lib/ext 서브디렉토리에 있다.

JRE는 사용자 정의할 수 있는 위치이지만 지정된 Java 환경 내에서 사용자 정의되는 경우가 거의 없기 때문에 lib/ext가 JAR을 저장하기에 안전한 위치이고 Java 환경의 CLASSPATH에서 JAR을 암묵적으로 사용할 수 있다고 생각해도 무방하다.

4. Java 6에서는 클래스 경로 와일드카드를 사용할 수 있다.

CLASSPATH 환경 변수(몇 년 전에 Java 개발자가 남겨 두어야 했던)와 명령행 -classpath 매개변수가 많아지는 것을 피하기 위해 Java 6에서는 클래스 경로 와일드카드라는 개념이 도입되었다. 클래스 경로 와일드카드를 사용하면 인수에 명시적으로 나열된 모든 JAR 파일을 하나하나 실행할 필요 없이 lib/*와 해당 디렉토리에 나열된 모든 JAR 파일(재귀적이지 않음)을 클래스 경로에 지정할 수 있다.

아쉽게도 클래스 경로 와일드카드는 앞에서 설명한 Class-Path 속성 매니페스트 항목에 적용되지 않는다. 하지만 코드 생성 도구 또는 분석 도구와 같은 개발자 태스크를 위한 Java 애플리케이션(서버 포함)을 쉽게 실행할 수 있다.

5. JAR에는 코드 이상의 것이 담겨 있다.

Java 에코시스템의 많은 부분과 마찬가지로 Spring도 환경의 설정 방법을 설명하는 구성 파일을 사용한다. 즉, Spring에서는 JAR 파일과 같은 디렉토리에 있는 app.xml 파일을 사용한다. 하지만 대부분의 개발자는 구성 파일을 JAR 파일과 함께 복사하는 것을 잊어버린다.

일부 구성 파일은 시스템 관리자가 편집할 수 있지만 하이버네이트 맵핑과 같은 상당 수의 구성 파일은 시스템 관리자 도메인의 외부에 있기 때문에 배치 작업 중에 발생하는 문제의 원인이 되고 있다. 합리적인 해결 방법은 구성 파일과 코드를 함께 패키지하는 것이다. 이는 JAR이 기본적으로 외형 상 ZIP 형식으로 되어 있기 때문에 가능한 방법이다. JAR을 빌드할 때 구성 파일을 Ant 태스크나 jar 명령행에 포함시키면 된다.

JAR은 구성 파일뿐만 아니라 다른 유형의 파일도 포함할 수 있다. 예를 들어, 필자는 특성 파일에 액세스할 필요가 있는 SpeakEnglish컴포넌트를 Listing 6과 같이 설정했다.


Listing 6. 임의로 응답하기
package com.tedneward.jars;

import java.util.*;

public class SpeakEnglish
    implements ISpeak
{
    Properties responses = new Properties();
    Random random = new Random();

    public String sayHello()
    {
        // Pick a response at random
        int which = random.nextInt(5);
        
        return responses.getProperty("response." + which);
    }
}

responses.properties를 JAR 파일에 넣는다는 것은 JAR 파일과 함께 배치할 파일이 하나 이상 있다는 것을 의미한다. 이 작업을 수행하려면 JAR 단계 동안 responses.properties 파일을 포함시켜야 한다.

특성을 JAR에 저장한 후 특성을 다시 가져오는 방법이 궁금할 수도 있을 것이다. 원하는 데이터가 동일한 JAR 파일 내에 함께 있는 경우에는 이전 예제에서 보았듯이 JAR 파일의 위치를 확인한 후 JarFile 오브젝트를 사용하여 JAR 파일을 열려고 시도하지 않아도 된다. 대신 ClassLoader getResourceAsStream() 메소드를 사용하여 클래스의 ClassLoader를 통해 JAR 파일 내에서 특성을 "자원"으로 찾는다(Listing 7 참조).


Listing 7. ClassLoader가 자원을 찾는다. 
package com.tedneward.jars;

import java.util.*;

public class SpeakEnglish
    implements ISpeak
{
    Properties responses = new Properties();
    // ...

    public SpeakEnglish()
    {
        try
        {
            ClassLoader myCL = SpeakEnglish.class.getClassLoader();
            responses.load(
                myCL.getResourceAsStream(
                    "com/tedneward/jars/responses.properties"));
        }
        catch (Exception x)
        {
            x.printStackTrace();
        }
    }
    
    // ...
}

구성 파일, 오디오 파일, 그래픽 파일 등을 포함한 모든 유형의 자원에 대해 이 프로시저를 수행할 수 있다. 실제로 모든 파일 유형을 JAR로 묶고, InputStream으로 가져온(ClassLoader를 통해) 다음 원하는 방식으로 사용할 수 있다.

결론

이 기사에서는 적어도 역사와 필자의 경험을 바탕으로 대부분의 Java 개발자가 JAR에 대해 모르고 있던 5가지 주요 사항을 살펴보았다. 이러한 JAR 관련 팁은 모두 WAR에도 동일하게 적용된다. WAR의 경우에는 서블릿 환경이 디렉토리의 전체 내용을 선택하고 사전 정의된 시작점이 있기 때문에 일부 팁(특히, Class-Path  Main-Class 속성)의 중요성이 낮을 수 있다. 하지만 전체적인 관점에서 이러한 팁은 "좋아, 이 디렉토리의 모든 항목을 복사하는 작업부터 시작하자..."라는 패러다임을 극복할 수 있도록 도와 준다. 결과적으로 Java 애플리케이션을 훨씬 더 간단하게 배치할 수도 있다.

이 시리즈의 다음 기사에서는 Java 애플리케이션의 성능 모니터링에 대해 모르고 있던 5가지 사항에 대해 살펴본다.


다운로드 하십시오

설명이름크기다운로드 방식
Sample code for this articlej-5things6-src.zip10KBHTTP

다운로드 방식에 대한 정보


참고자료

교육

  • 5 things you didn't know about ...(Ted Neward 저, developerworks): 이 새 시리즈는 Java의 사소한 기능에 큰 가치를 부여한다. 

  • "JAR 파일"(Pagadala Suresh 및 Palaniyappan Thiagarajan 저, developerWorks, 2003년 10월): 패키징, 실행 가능한 JAR 파일, 보안 및 색인을 포함한 Java Archive 형식의 특징과 장점에 대해 소개한다. 

  • Packaging programs in JAR files(The Java Tutorials trail): JAR에 대한 기본적인 정보를 볼 수 있다. 

  • Spring: 소스를 통해 직접 이 강력하고 유연하며 유명한 프레임워크에 대한 정보를 볼 수 있다. 

  • "Dependency injection with Guice"(Nicholas Lesiecki 저, developerworks, 2008년 12월): DI는 관리성, 테스트 가능성 및 유연성을 높여 주며, Guice는 DI를 쉽게 사용할 수 있도록 지원한다. 

  • "Setting multiple jars in java classpath"(StackOverflow Q&A, 마지막 갱신 날짜: 2010년 3월): 클래스 경로 와일드카드에 대한 자세한 정보를 볼 수 있다. 

  • "See JARs run"(Shawn Silverman 저, JavaWorld.com, 2002년 5월): 이 튜토리얼에서는 실행 가능한 JAR 파일을 작성하는 방법에 대해 자세히 설명한다. 

  • "Advanced topics in programming languages series: JSR 277: Java Module System"(Google Tech Talks, 2007년 5월): JAR에는 클래스 경로, JAR 파일, 확장 등과 관련된 단점이 있다. 이 Google Tech Talk에서는 JSR 277이 이러한 단점을 해결하는 방법에 대해 설명한다. 

  • developerWorks Java 기술 영역: Java 프로그래밍과 관련된 모든 주제를 다루는 여러 편의 기사를 찾아보자. 

토론

필자소개

Ted Neward는 글로벌 컨설팅 업체인 ThoughtWorks의 컨설턴트이자 Neward & Associates의 회장으로 Java, .NET, XML 서비스 및 기타 플랫폼에 대한 컨설팅, 조언, 교육 및 강연을 한다. 워싱턴 주의 시애틀 근교에 살고 있다.


출처 - http://www.ibm.com/developerworks/kr/library/j-5things6.html








'Development > Java' 카테고리의 다른 글

java - Executor  (0) 2012.11.16
java - CGLIB(Code Generator Library) 코드 생성 라이브러리  (0) 2012.11.12
java 로드맵  (0) 2012.11.07
java - enum  (0) 2012.11.05
java - @Override  (0) 2012.11.03
Posted by linuxism
,