마인드진 공간 블로그

블로그 이미지
안드로이드 어플을 개발하고 있는 개발자 입니다.
by 마인드진

빈공간 줄이기.

Java2010. 6. 13. 17:53

//   for(int x=0; x< obList.size(); x++){
//    String str = obList.get(x);
//    String[] strArray = str.split(" ");
//    strArray[strArray.length-1] = strArray[strArray.length-1].trim();
//
//
//    str = "";
//    for(int j = 0; j < strArray.length-1; j++){
//     str += strArray[j]+" ";
//    }
//
//    str = strArray[strArray.length-1];
//    obList.set(x, str);

'Java' 카테고리의 다른 글

빈공간 줄이기.  (0) 2010.06.13
자바 세미나  (0) 2010.03.15
자바 중복 제거  (0) 2010.03.04
[자바] 현재 시간을 출력하는 함수  (0) 2010.03.03
컬렉션  (0) 2010.02.12
SSL 서버  (0) 2009.12.29

Comment +0

자바 세미나

Java2010. 3. 15. 14:23

  • 자바 개발자를 위한 'Java 2010' 기업형 자바, 브라우저에서 모바일로
    •  

      자바(Java)에 대한 관심이 더욱 증폭되고 있습니다. 지난해 중순 까지는 오픈소스(공개형 SW) 덕분이었다고 한다면
      이제는 ’안드로이드’ 돌풍 때문입니다.


      자바 개발자 역시 이러한 흐름에 맞춰 자기 계발에 최선을 다하고 있습니다. 이럴 때일수록 어떤 흐름과 추세에 맞춰
      미래를 준비하고 계획해야 하는지 멘토링이 절실히 필요한 시기입니다.


      자바모델링, OKJSP, 안드로이드펍 등 대표 커뮤니티가 뭉쳤습니다. 이들과 함께 하는 ’Java 2010’ 성공 스토리가 시작 됩니다. 자바와 안드로이드에 관심 있는 모든 분을 환영합니다.


      공개SW를 활용한 기업형 자바가 브라우저에서 모바일로 어떻게 어떤 기능들이 구현되는지와 모바일에서 공개SW의 가능성을 살펴보는 자리를 마련했습니다.

       

      일   시 : 2010.3.27(토)  12:30 ~ 18:00

      장   소 :  잠실교통회관 대강당 (잠실역)   약도보기

      참가인원 : 500여명 (선착순 접수 및 입금 순서대로 마감합니다.)

      참 가 비 : 사전접수 11,000원(부가세포함)

                   현장 접수 22,000원(부가세포함)

                      입금계좌 : 1005-001-359229 우리은행  예금주 : (주)모자이크넷

      주최 :

       

       

      주관 :

       

       

      후원 :

       

       

      무통장입금 후 입금확인 이메일을 보내주세요. 
      입금확인 이메일 : sinjung18@devmento.co.kr  (02 - 529 0091)
      법인일 경우 전자세금계산서(개인, 현금영수증)가 필요하신 경우 입금처리후 사업자등록증을
      이메일이나 팩스 (02 - 529 - 0092)로 보내주시고 받으실 이메일핸드폰번호를 꼭 기입해 주시기를 바립니다.

      * 전자세금 계산서를 받으신후 이메일이나 문자로 확인후 승인해주세요. 

      *주차지원은 따로 하지 않습니다. 대중교통 이용을 권합니다.

      http://www.devmento.co.kr/dtfe/seminar/edumento_detail.jsp?main_id=SDTF3W001&dataSeq=41

    'Java' 카테고리의 다른 글

    빈공간 줄이기.  (0) 2010.06.13
    자바 세미나  (0) 2010.03.15
    자바 중복 제거  (0) 2010.03.04
    [자바] 현재 시간을 출력하는 함수  (0) 2010.03.03
    컬렉션  (0) 2010.02.12
    SSL 서버  (0) 2009.12.29

    Comment +0

    자바 중복 제거

    Java2010. 3. 4. 16:55

    import java.util.ArrayList;

    public String[] getUniqueStringArray(String[] strArray) {
      ArrayList list = new ArrayList();
      for ( int i=0; i<strArray.length; i++ ) {
        if ( ! list.contains(strArray[i]) ) list.add(strArray[i]);
      }
      String uniqueArray[] = new String[list.size()];
      list.toArray(uniqueArray);
      return uniqueArray;
    }

     

    리스트에 들어있는 중복 데이터들 중 중복 제거시 유용한 메소드.

    [출처] Java 중복 제거|작성자 남박사

    'Java' 카테고리의 다른 글

    빈공간 줄이기.  (0) 2010.06.13
    자바 세미나  (0) 2010.03.15
    자바 중복 제거  (0) 2010.03.04
    [자바] 현재 시간을 출력하는 함수  (0) 2010.03.03
    컬렉션  (0) 2010.02.12
    SSL 서버  (0) 2009.12.29

    Comment +0


    long now = System.currentTimeMillis();

    SimpleDateFormat sdfNow = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String strNow = sdfNow.format(new Date(now));

    얼마나 걸리는지 테스트 해보기에 안성맞춤 .. !!!

    'Java' 카테고리의 다른 글

    자바 세미나  (0) 2010.03.15
    자바 중복 제거  (0) 2010.03.04
    [자바] 현재 시간을 출력하는 함수  (0) 2010.03.03
    컬렉션  (0) 2010.02.12
    SSL 서버  (0) 2009.12.29
    [JAVA] 컴파일러 들여다보기  (0) 2009.12.24

    Comment +0

    컬렉션

    Java2010. 2. 12. 11:31

    ArrayList

    컬렉션이란 자료의 집합을 관리하는 자료 구조이다. 가장 간단하게는 배열이 있지만 배열은 재할당할 수 없어 최초 생성한 크기 이상을 저장할 수 없다는 약점이 있다. 컬렉션은 실행중에 메모리를 자동으로 재할당하므로 가변 크기의 자료들을 저장하는데 적합하다.

    가장 대표적이고도 실용적인 컬렉션이 ArrayList이다. 배열과 메모리 관리 방법이 유사하되 실행중에 요소의 개수에 따라 동적으로 크기를 늘릴 수 있고 배열 중간에도 삽입, 삭제가 자유롭다는 차이점이 있다. 템플릿 클래스이므로 <> 괄호안에 저장하고자 하는 데이터의 타입 파라미터를 밝혀야 한다. 생성자는 다음과 같다.

     

    ArrayList<E>()

    ArrayList<E>(int initialCapacity)

     

    디폴트 생성자는 크기 10의 배열을 초기 할당한다. 어차피 실행중에 필요한만큼 메모리가 늘어나므로 초기 크기는 중요하지 않다. 하지만 매번 재할당하면 속도가 느려지므로 대용량의 자료를 관리해야 한다면 초기 크기를 전달하여 처음부터 메모리를 크게 할당해 놓는 것이 유리하다. 요소를 추가할 때는 다음 메서드를 호출한다.

     

    boolean add(E e)

    void add(int index, E element)

     

    요소만 전달하면 배열의 끝에 추가되고 위치까지 같이 전달하면 지정한 위치에 삽입된다. 중간에 끼어들면 뒤쪽의 요소들은 자동으로 한칸씩 뒤로 이동한다. 배열의 현재 크기를 조사할 때는 size 메서드를 호출하며 배열이 비어 있는지만 알고 싶을 때는 isEmpty 메서드를 호출한다.

     

    int size()

    boolean isEmpty()

     

    비어 있다는 것은 요소 개수가 0이라는 것과 같으므로 size() == 0 조건문으로도 조사할 수 있다. 그러나 큰 배열의 경우는 개수를 전부 세는 것 자체가 시간을 많이 소모할 수도 있으므로 비어 있는지만 알고 싶을 때는 isEmpty 메서드가 더 빠를 것이다. 배열의 요소를 읽거나 변경할 때는 다음 두 메서드를 사용한다.

     

    E get(int index)

    E set(int index, E element)

     

    get 메서드로 읽고자 하는 배열의 첨자를 전달하면 이 첨자에 저장된 요소가 읽혀진다. 이때 첨자는 반드시 배열의 크기보다 작아야 하여 범위를 벗어나면 IndexOutOfBounds 예외가 발생한다. 요소를 삭제할 때는 다음 메서드를 사용한다.

     

    E remove(int index)

    void removeRange(int fromIndex, int toIndex)

    void clear()

     

    첨자를 지정하여 한 요소만 삭제할 수도 있고 일정 범위의 요소를 삭제할 수도 있다. clear 메서드는 모든 요소를 전부 다 삭제한다. 다음 두 메서드는 배열에서 요소를 찾는다.

     

    int indexOf(Object o)

    int lastIndexOf(Object o)

     

    검색하고자 하는 요소를 인수로 전달하면 이 요소가 발견되는 위치를 리턴한다. 발견되지 않으면 -1이 리턴된다. indexOf는 배열의 앞쪽부터 검색을 하며 lastIndexOf는 뒤쪽에서부터 검색을 시작한다. 배열에 똑같은 요소가 여러 개 존재하는 경우 어떤 메서드로 검색을 하는가에 따라 결과가 달라질 수도 있다. 다음 예제는 ArrayList의 여러 가지 메서드를 순서대로 호출해 본다.

     

    import java.util.*;

    class JavaExam {

         public static void main(String args[]) {

              ArrayList<String> arName = new ArrayList<String>();

              arName.add("전두환");

              arName.add("김영삼");

              arName.add("김대중");

              arName.add(1,"노태우");

              for (int i = 0;i < arName.size();i++) {

                  System.out.println(arName.get(i));

              }

     

              System.out.println("==========");

              arName.remove(2);

              arName.set(2,"원더걸스");

              for (int i = 0;i < arName.size();i++) {

                  System.out.println(arName.get(i));

              }

              if (arName.indexOf("노태우") != -1) {

                  System.out.println("있다");

              } else {

                  System.out.println("없다");

              }

         }

    }

     

    문자열을 저장하는 arName 배열을 선언하고 초기화했다. 생성자의 인수로 초기값을 전달하지 않았으므로 최초 10개의 요소를 저장할 수 있는 크기로 생성될 것이다. add 메서드로 전두환, 김영삼, 김대중을 차례대로 추가했다. 추가된 순서대로 배열의 선두부터 차례대로 기억된다. 노태우는 1번 위치에 삽입했다. 전두환과 김영삼 사이에 노태우가 끼어들 것이다.

    배열을 순회할 때는 0부터 시작해서 size 메서드로 조사한 배열 크기 직전까지 순회하면서 get 메서드로 첨자 위치의 요소를 읽으면 된다. 정적 배열과 마찬가지로 시작 첨자는 항상 0이며 마지막 첨자는 크기보다 1 작다. 배열의 모든 요소들을 출력해 보았는데 역대 대통령 순으로 출력될 것이다.

    다음은 remove 메서드로 2번 요소를 삭제했는데 김영삼이 삭제된다. 중간에 요소가 삭제되면 뒤쪽의 요소들이 한칸씩 앞쯕으로 이동하므로 김대중이 2번 요소가 될 것이다. set 메서드로 2번 요소를 원더걸스로 바꾸어 보았다. 김영삼은 사라지고 김대중은 원더걸스로 바뀔 것이다. 마지막으로 indexOf로 노태우 요소가 아직 있는지를 점검해 보았다.

     

    전두환

    노태우

    김영삼

    김대중

    ==========

    전두환

    노태우

    원더걸스

    있다

     

    ArrayList에 저장되는 요소들은 참조형만 가능하며 기본형은 저장할 수 없다. 실행중에 힙에 동적으로 할당되어야 하기 때문이다. 만약 기본형을 저장하고 싶다면 이때는 앞에서 배운 래퍼 클래스로 박싱하여 저장해야 한다. 다음 예제는 정수를 컬렉션에 저장한다.

     

    import java.util.*;

    class JavaExam {

         public static void main(String args[]) {

              ArrayList<Integer> arNum = new ArrayList<Integer>();

              arNum.add(86);

              arNum.add(92);

              arNum.add(77);

              for (Integer i : arNum) {

                  System.out.println(i);

              }

         }

    }

     

    ArrayList<int> 타입은 허용되지 않으므로 int를 래핑하는 Integer 타입을 사용해야 한다. 이외에도 ArrayList에는 컬렉션을 배열로 변환하는 toArray 메서드와 뒤쪽의 여유 메모리를 회수하는 trimToSize 메서드가 제공된다.

    LinkedList

    ArrayList는 요소들을 인접한 메모리에 저장하기 때문에 읽기 속도가 굉장히 빠르다. 원하는 첨자에 요소 타입의 크기를 곱하기만 하면 원하는 값을 바로 구할 수 있다. 그러나 요소들이 계속 인전한 상태를 유지하기 위해 중간에 삽입, 삭제할 때 뒤쪽의 요소들을 이동시켜야 하므로 삽입, 삭제 속도는 느리다.

    LinkedList는 ArrayList와는 완전히 반대되는 성질을 가진다. 요소들을 인접한 메모리에 저장하는 것이 아니라 힙의 아무 곳에나 저장하되 링크로 서로 연결하여 앞뒤 순서를 구별한다. 중간에 요소를 삽입 삭제하더라도 메모리를 이동할 필요없이 링크만 조작하면 되므로 삽입, 삭제 속도가 빠르다. 그러나 임의 위치의 요소를 읽으려면 처음부터 순서대로 링크를 따라 가야 하므로 읽기 속도는 느리다.

    이 둘은 사용 용도가 완전히 같아서 서로 대체 가능하다. 내부적인 구조가 다름으로 인해 메모리 사용량에서 차이가 나고 읽기, 쓰기 동작의 속도차가 날 뿐이다. 읽기 동작이 빈번하면 ArrayList를 쓰는 것이 유리하고 삽입, 삭제가 빈번하면 LinkedList를 쓰는 것이 유리하다. 그러나 일반적으로는 읽기가 쓰기보다 훨씬 더 중요하기 때문에 ArrayList가 대부분의 경우에 더 좋은 성능을 보여 준다.

    둘 다 똑같은 용도로 사용하는 클래스이므로 인터페이스도 거의 비슷하다. 다만 LinkedList에는 다음 메서드들이 추가로 제공된다. 리스트의 첫 위치에 삽입하거나 첫 위치의 요소를 읽는데 이 메서드들도 사실 add(0, e), get(0)와 동일하므로 특별한 것도 아니다.

     

    void addFirst(E e)

    E getFirst()

     

    다음 예제는 연결 리스트로 역대 대통령을 저장해 보고 다시 출력한다.

     

    import java.util.*;

    class JavaExam {

         public static void main(String args[]) {

              LinkedList<String> arName = new LinkedList<String>();

              arName.add("전두환");

              arName.add("김영삼");

              arName.add("김대중");

              arName.add(1,"노태우");

             

              for (int i = 0;i < arName.size();i++) {

                  System.out.println(arName.get(i));

              }

         }

    }

     

    컬렉션 클래스의 이름이 바뀌었을 뿐 사용하는 방법은 완전히 동일하다. 중간에 노태우를 삽입할 때의 속도가 조금 더 빠르겠지만 실측할 수 없을 정도로 근소한 차이가 난다. 실행 결과도 물론 앞 예제와 동일하다.

     

    전두환

    노태우

    김영삼

    김대중

     

    그러나 연결 리스트는 배열에 비해 요소를 읽는 속도가 느려 출력에는 상당히 불리하다. 요소가 기껏 4개밖에 없어서 차이를 느낄 수 없지만 100개 정도만 되도 차이가 벌어진다. 왜냐하면 연결 리스트는 get 메서드가 상당히 비효율적으로 동작하기 때문이다. 임의 위치의 한 요소를 읽을 때마다 리스트의 처음부터 순회를 해 와야 한다. 위 예제의 for 루프는 형태상으로는 단순 루프이지만 내부에 헤더부터 i번째 요소까지 링크를 따라가는 코드가 포함되어 있어 실제로는 이중 루프이다.

    이런 약점을 극복하기 위해 연결 리스트는 반복자라는 것을 제공한다. 반복자는 링크의 현재 위치를 저장해 두는 객체이며 저장된 위치에서 바로 다음칸으로 이동할 수 있어 링크를 따라 순회할 때 훨씬 더 효율이 좋다. 코드를 다음과 같이 수정해 보자.

     

    Iterator<String> it = arName.iterator();

    while (it.hasNext()) {

         System.out.println(it.next());

    }

     

    리스트의 iterator 메서드를 호출하면 리스트의 요소들을 순회할 수 있는 반복자가 리턴되는데 이 반복자는 리스트의 요소 타입을 가리키므로 선언문에 순회할 데이터의 타입을 파라미터로 밝혀야 한다. 반복자는 최초 리스트의 헤더를 가리키며 next 메서드로 다음 요소로 링크를 따라 이동한다.

    next는 요소를 읽어 리턴하기 때문에 리스트의 끝에서 에러를 리턴할만한 장치가 없다. 그래서 리스트의 끝에 닿으면 예외를 발생시킨다. 이 예외를 방지하려면 next로 이동하기 전에 hasNext 메서드를 호출하여 뒤쪽에 아직 요소가 있는지를 먼저 점검해 보아야 한다. 실행결과는 for 루프를 돌리는 것과 다를 게 없다. 그러나 리스트에 요소가 많을 때는 반복자를 쓰는 것이 확실히 더 빠르다.

    HashMap

    해시는 빠른 검색을 위해 데이터를 미리 정해진 규칙에 따라 일정한 장소에 저장하는 기법이다. 대용량의 버킷을 마련해 놓고 해쉬 코드에 따라 버킷 번호를 선택해 저장해 두면 검색시에 해쉬 코드를 구하는 간단한 연산으로 원하는 값을 바로 구할 수 있다. 자세한 것은 자료 구조 관련 서적을 참조하기 바란다.

    자바는 HashMap 클래스로 해시를 제공한다. 키와 값에 대해 두 개의 타입을 파라미터로 전달한다. put 메서드로 키와 값의 쌍을 해시에 저장하며 get 메서드로 키를 전달하면 원하는 값을 빠른 속도로 검색할 수 있다.

     

    import java.util.*;

    class JavaExam {

         public static void main(String args[]) {

              HashMap<String,Integer> Snack = new HashMap<String,Integer>();

              Snack.put("오징어 땅콩", 2500);

              Snack.put("죠리퐁", 1900);

              Snack.put("핫브레이크", 450);

              Snack.put("빼빼로", 900);

             

              String MySnack = "죠리퐁";

              System.out.println(MySnack + "의 가격은 " + Snack.get(MySnack));

         }

    }

     

    과자의 이름과 가격을 해시에 저장해 놓고 검색해 보았다. 항목이 몇 개 안되므로 이 정도로는 해시의 빠른 검색 속도를 실감하기 어려울 것이다. 항목의 개수가 아무리 많아도 거의 실시간으로 검색된다. 거짓말 안보태고 수억개가 넘어도 검색 시간은 순간이다. 대신 메모리는 좀 많이 먹는다.

    사용자가 작성한 클래스를 해시의 키로 사용하려면 hashCode 메서드를 재정의하여 해시 코드가 고르게 분포되도록 해야 한다. 이때 equals 메서드도 같이 재정의해야 한다.

    출처 : http://www.winapi.co.kr/

    'Java' 카테고리의 다른 글

    자바 중복 제거  (0) 2010.03.04
    [자바] 현재 시간을 출력하는 함수  (0) 2010.03.03
    컬렉션  (0) 2010.02.12
    SSL 서버  (0) 2009.12.29
    [JAVA] 컴파일러 들여다보기  (0) 2009.12.24
    자바에서 구조체사용..  (0) 2009.12.23

    Comment +0

    SSL 서버

    Java2009. 12. 29. 17:04

    SSL 서버
    지난 테크팁 'JSSE를 이용한 안전한 커뮤니케이션'에서 클라이언트측으로부터의 보안 HTTP 요청과 반응(HTTPS또는 HTTP over SSL)을 어떻게 핸들링하는지 배웠다. 이번 팁에서는 서버측 부분의 SSL 커뮤니케이션에 대해서 알아보기로 한다.

    첫번째 팁 Working with Selectors에서와 같이 이번 팁의 서버는 에코 서버이다. 즉 서버는 클라이언트로부터 수신한 것을 단순히 클라이언트에게 재송신한다.

    Again, 클라이언트 측 테크팁에서의 경우과 같이 서버를 생성하기 위해 먼저 소켓 팩토리를 얻는다. SSL 서버용 소켓을 위해서 SSLServerSocketFactory 타입 팩토리를 이용한다. SSLServerSocketFactory는 javax.net.ssl 패키지에 있다.

       ServerSocketFactory sslserversocketfactory =
         SSLServerSocketFactory.getDefault();

    그 후 서버 소켓을 얻고 accept와 연결되기를 기다린다.

       ServerSocket serverSocket =
         serverSocketFactory.createServerSocket(PORT_NUM);
       Socket socket = serverSocket.accept();

    나머지 서버 코드는 단순하다. "SelectorTest"팁과 비슷하여, 클라이언트가 전송하는 것을 단지 읽고 다시 재전송하기만 하면 된다. 다음은 서버 코드 전체이다.

       import javax.net.ssl.*;
       import javax.net.*;
       import java.io.*;
       import java.net.*;

       public class EchoServer {
         private static final int PORT_NUM = 6789;
         public static void main(String args[]) {
           ServerSocketFactory serverSocketFactory =
             SSLServerSocketFactory.getDefault();
           ServerSocket serverSocket = null;
           try {
             serverSocket =
               serverSocketFactory.createServerSocket(PORT_NUM);
           } catch (IOException ignored) {
             System.err.println("Unable to create server");
             System.exit(-1);
           }
           while(true) {
             Socket socket = null;
             try {
               socket = serverSocket.accept();
               InputStream is = socket.getInputStream();
               BufferedReader br = new BufferedReader(
                 new InputStreamReader(is, "US-ASCII"));
               OutputStream os = socket.getOutputStream();
               Writer writer =
                 new OutputStreamWriter(os, "US-ASCII");
               PrintWriter out = new PrintWriter(writer, true);
               String line = null;
               while ((line = br.readLine()) != null) {
                 out.println(line);
               }
             } catch (IOException exception) {
               exception.printStackTrace();
             } finally {
               if (socket != null) {
                 try {
                   socket.close();
                 } catch (IOException ignored) {
                 }
               }
             }
           }
         }
       }

    그러나 이 프로그램을 구동하기 전에 한가지 문제가 있다. 인증서가 없다는 것이다. 특정 인증서 없이 이 프로그램을 구동하면 SSLException을 얻게 된다.

       javax.net.ssl.SSLException: No available certificate
        corresponds to the SSL cipher suites which are enabled.
          at com.sun.net.ssl.internal.ssl.SSLServerSocketImpl.a(DashoA6275)
          at com.sun.net.ssl.internal.ssl.SSLServerSocketImpl.accept(DashoA6275)
          at EchoServer.main(EchoServer.java:21)

    SDK와 함께 제공되는 키툴(keytool) 프로그램으로 인증서를 생성할 수 있다. 키페어(keypair)를 생성하는 -genkey 옵션, 키 스토어 파일(key store file)을 지정하는 -keystore옵션, 암호 알고리즘을 지정하는 -keyalg 옵션이 포함된 keytool 커멘드를 실행하자.

       keytool -genkey -keystore testStore -keyalg RSA

    그러면 몇가지 정보입력을 위한 질문을 받게될 것이다. 적절한 정보를 제공하면 된다. 다음은 예상되는 다이얼로그의 한 예이다.

       Enter keystore password:  tutorial
       What is your first and last name?
         [Unknown]:  Sun Tutorial
       What is the name of your organizational unit?
         [Unknown]:  Sun
       What is the name of your organization?
         [Unknown]:  Sun
       What is the name of your City or Locality?
         [Unknown]:  Santa Clara
       What is the name of your State or Province?
        [Unknown]:  CA
       What is the two-letter country code for this unit?
        [Unknown]:  US
       Is CN=Sun Tutorial, OU=Sun, O=Sun, L=Santa Clara,
        ST=CA, C=US correct?
         [no]:  yes
     
       Enter key password for <mykey>
               (RETURN if same as keystore password):

    일반적으로 CN 엔트리(이름)는 필수적인 요청사항은 아니지만, 서버의 호스트명이 되어야한다. 위의 예에서 클라이언트가 localhost로 서버에 접근하기 때문에, 그 이름이 필히 사용될 것이다.

    커멘드를 구동한 후에는, 작업하고 있는 디렉토리에서 testStore라는 이름의 새로운 파일을 발견하게 될 것이다. 이제 SSL을 이용하여 서버를 구동시킬 수 있다. 서버를 구동하는 커멘드를 송신할 때 javax.net.ssl.keyStore 속성으로 키 스토어를 식별하고 javax.net.ssl.keyStorePassword로 키 스토어의 패스워드를 식별한다.

      java -Djavax.net.ssl.keyStore=testStore
           -Djavax.net.ssl.keyStorePassword=tutorial EchoServer

    물론 이 때 서버와 커뮤니케이션 할 클라이언트가 필요하다. 다음의 클라이언트는 커멘드 라인으로부터의 입력을 읽고, 서버에 그 입력을 송신한 후 되돌아 온 응답을 작성한다.

       import javax.net.ssl.*;
       import javax.net.*;
       import java.io.*;
       import java.net.*;

       public class EchoClient {
         private static int PORT_NUM = 6789;
         private static String host = "localhost";
         public static void main(String args[])
             throws IOException {
           SocketFactory socketFactory =
             SSLSocketFactory.getDefault();
           Socket socket = socketFactory.createSocket(
             host, PORT_NUM);

           BufferedReader br = new BufferedReader(
             new InputStreamReader(System.in, "US-ASCII"));
           PrintWriter out = new PrintWriter(
             new OutputStreamWriter(
               socket.getOutputStream(), "US-ASCII"), true);

           BufferedReader socketBr = new BufferedReader(
             new InputStreamReader(
               socket.getInputStream(), "US-ASCII"));

           String string = null;
           System.out.print("First line: ");
           while (!(string = br.readLine()).equals("")) {
             out.println(string);
             String line = socketBr.readLine();
             System.out.println("Got Back: " + line);
             System.out.print("Next line: ");
           }
           socket.close();
         }
       }

    클라이언트를 컴파일하자. 클라이언트를 구동하기 위해서는 서버를 시작할 때 지정한 것과 같은 인증서를 지정해야한다. 그렇지 않으면 클라이언트가 서버에 연결하기 위해 시도할 때 서버에 SSLHandshakeException이 발생한다.

       javax.net.ssl.SSLHandshakeException: Remote host closed
         connection during handshake

    클라이언트를 시작할 때 키 스토어 대신 트러스트 스토어로서 인증서를 참조해보자.

       java -Djavax.net.ssl.trustStore=testStore
         -Djavax.net.ssl.trustStorePassword=tutorial EchoClient

    그러면 클라이언트가 SSL을 통해 서버와 커뮤니케이션 하게 될 것이다.

       First line: Hello
       Got Back: Hello
       Next line: There
       Got Back: There
       Next line: Server
       Got Back: Server

    한 머신 안에서 인증서를 공유하는 것은 쉽다. 그러나 여러 머신에서 인증서를 공유하기 위해서는 외부 클라이언트 머신에 인증서를 발행하는 것이 필요하다. 단순히 "testStore" 키스토어를 복사할 수 있지만, 그렇게 되면 사용자의 개인 키를 노출하게 되어 아무나 그 사용자인양 위장할 수 있게 된다. 따라서 그 대신에 키툴 프로그램의 -export 와 -import옵션을 사용할 수 있다. 키스토어의 공개 가능한 인증서를 익스포트하자. 그러면 당신을 신뢰하는 누군가가 그들의 머신으로 인증서를 임포트할 것이다. 이 작업은 여러 머신에 여러 번 가능하다. 외부 머신이 인증서를 임포트한 후에는 그 머신의 클라이언트와 SSL을 통해 커뮤니케이션 할 수 있다.

    SSL 사용에 대한 좀 더 자세한 정보를 원한다면 Java Secure Socket Extension (JSSE) Reference Guide를 참고하기 바란다.

    [출처] SSL 서버|작성자 선성환


    'Java' 카테고리의 다른 글

    자바 중복 제거  (0) 2010.03.04
    [자바] 현재 시간을 출력하는 함수  (0) 2010.03.03
    컬렉션  (0) 2010.02.12
    SSL 서버  (0) 2009.12.29
    [JAVA] 컴파일러 들여다보기  (0) 2009.12.24
    자바에서 구조체사용..  (0) 2009.12.23

    Comment +0

    마이크로소프트웨어 2006년 7월 기고글입니다.


    자바 개발자라면 누구나 자바 컴파일러(javac)를 사용한다. 하지만 상당수 개발자는 컴파일러가 어떻게 동작하는지 관심이 없다.이들은 작성한 소스 코드가 오류 없이 컴파일되고 컴파일의 결과로 나온 클래스 파일이 원하는 기능을 수행하면 그만이라고 말한다.하지만 컴파일러 작성자가 아니더라도 컴파일러가 소스 코드를 어떤 형태의 바이너리(자바의 경우 바이트코드)로 변환시키는지 알아두면유용한 경우가 많다. 이 글에서는 몇 가지 예제를 중심으로 자바 컴파일러의 내부 동작을 엿보는 기회를 가지려고 한다.


    T 업계의 종사하는 사람이라면 18개월마다 컴퓨팅 파워가 2배가 된다는 무어(Moore)의 법칙을 잘 알고 있을 것이다. 컴파일러에도 이와 비슷한 법칙이 있다.


    Proebsting's Law

    컴파일러 기술은 18년마다 컴퓨팅 파워(computing power)를 2배로 증가시킨다.


    이 법칙이 정확한 예측치는아니더라도 비약적으로 발전하는 하드웨어에 비해 컴파일러의 발전 속도가 상당히 더디다는 것만은 유추할 수 있다. 하지만 그렇다고마냥 정체되어 있기만 한 것은 아니었다. 50-60년대에 최초의 컴파일러가 나오고 벌써 수십 년이 지났으므로, 지금 우리가사용하는 컴파일러는 초창기에 비해 상당히 발전한 것이다.

    따라서 개발자도 컴파일러를블랙박스로만 생각할 것이 아니라, 어떤 일을 해주는지 조금은 알아둘 필요가 있다. 컴파일러가 변환하는 소스 코드와 바이너리의관계를 코드 모양(code shape)이라고 하는데, 최적화 컴파일러의 복잡한 변환(transformation) 과정은아니더라도, 이런 코드 모양을 몇 가지 숙지하고 있으면 좋다. 이 글에서는 자바의 표준 컴파일러인 javac을 통해 자바 언어와바이트코드에 대한 이해의 폭을 넓혀 보려고 한다.


    데드 코드(dead code)와 조건부 컴파일


    C/C++개발자들이 자바 개발을 시작하면 가장 먼저 느끼는 불편함 중에 하나가 전처리기(preprocessor)의 부재일 것이다.C/C++에서는 #ifdef #endif를 이용해서 특정 코드를 선택적으로 컴파일할 수 있는데, 자바는 그런 전처리기가 없기때문이다. 하지만 자바 컴파일러를 잘 이용하면 자바에서도 조건부 컴파일이 가능하다. 우선 자바 컴파일러의 배경 지식부터 살펴보자.

    컴파일러는 바이너리를 생성하기에앞서서 실행 흐름 분석(control flow analysis)을 통해 소스 프로그램을 분석하는데, 이 분석을 통해 하는 일중에 하나가 데드 코드 제거(dead code elimination)이다. 자바 컴파일러도 프로그램 흐름상 절대로 수행될 수없는 코드를 발견하면 이 부분은 바이트코드에 포함시키지 않는다. 다음 예제를 보자.


    <!--[if !supportEmptyParas]-->

    public class Foo {

         public static void main(String args[]) {

             if (false) {

                 System.out.println("Never");

             }

         }

    }

    데드 코드 예제


    자바 디컴파일러 javap

    자바 개발 환경을 설치하면 javac,java와 함께 몇 가지 프로그램이 함께 설치되는데, 그 중 하나가 자바 디컴파일러인 javap이다. javap는 클래스 파일을읽어서 클래스와 메쏘드, 그리고 각 메쏘드의 바이트코드를 보여주는 프로그램이다. 특히 자바 네이티브 인터페이스(JavaNative Interface, JNI) 작성 시에 메쏘드 시그너처(signature)를 뽑아내는데 유용한 도구이다. -c옵션을 주면 각 메쏘드의 바이트코드도 볼 수 있는데, 이 글의 디컴파일 결과는 모두 javap -c를 사용한 것이다.


    위 코드에서 if(false) System.out.println("Never")은 수행될 수 없는 코드이다. 따라서 바이트코드에 포함되지않는데, 자바 디스어셈블러인 javap를 이용해 Foo.class를 살펴보면 main 메쏘드에 return 문만 있는 것을 볼수 있다.


    public static void main(java.lang.String[]);

    Code:

    0: return

    <!--[if !supportEmptyParas]--> 데드 코드 Foo의 디컴파일

    <!--[endif]-->


    물론 if (false)의경우는 너무 당연해서 별로 쓸모가 있어 보이지 않는다. 하지만 자바 컴파일러가 데드 코드를 바이트코드에 포함시키지 않는다는사실을 이용하면 C/C++ 전처리기리처럼 조건부 컴파일을 흉내 낼 수 있다. 다음 예제를 살펴보자.


    class Configure {

         public static final boolean debug = false;

    }

    <!--[if !supportEmptyParas]--> <!--[endif]-->

    public class Foo {

         public static void main(String args[]) {

             if (Configure.debug) {

                 System.out.println("Debug.");

             }

         }

    }

    조건부 컴파일 예제


    [debug가 static final인 경우]

    public static void main(java.lang.String[]);

    Code:

    0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;

    3: ldc #3; //String Debug.

    5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

    8: return

    조건부 컴파일 디컴파일


    자바에서 static final로선언된 필드는 상수(constant)이다. 따라서 위 조건부 컴파일 예제의 경우 Configure.debug라는 플래그가false이면 main 메쏘드의 if (Configure.debug) 부분이 데드 코드가 되므로 바이트코드에 포함되지 않는다.반대로 debug를 true로 바꿔주면, if (Configure.debug) 부분 코드가 컴파일되는데, debug는static final로 선언되어 있으므로 항상 참이다. 따라서 javac은 if 문을 없애고 바로System.out.println을 실행하도록 코드를 생성한다. 즉 flag를 true/false로 바꿔준 후에 새로 컴파일하면조건부 컴파일이 되는 것이다.


    [debug가 final이 아닌 경우]

    public static void main(java.lang.String[]);

    Code:

    0: getstatic #2; //Field Configure.debug:Z

    3: ifeq 14

    6: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;

    9: ldc #4; //String Debug.

    11: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

    14: return

    final이 아닌 경우 디컴파일


    만약에 debug가 final이 아니었다면 런타임에 값이 바뀔 수 있으므로, [debug가 false가 아닌 경우]의 3행에서처럼 ifeq로 debug 값을 테스트하는 부분이 들어갔을 것이다.


    배열 초기화(array initialization)


    C/C++프로그램을 개발할 때 바이너리 데이터를 메모리에 읽어오는 방법으로 배열 초기화를 사용하는 경우가 많다. 특히 바이너리 외에별도의 파일 시스템이 없는 임베디드 시스템의 경우 어플리케이션의 그림(image)나 소리(sound) 데이터를 char[]에저장한다. 로더(loader)가 프로그램을 로드할 때 배열의 값을 메모리의 데이터 영역으로 바로 복사해주기 때문에 효율적이다.

    다음은 썬(Sun)에서 만든 J2ME의 Personal Basic Profile 소스 코드에서 발췌한 코드이다.


    class IxcClassLoader extends ClassLoader {

    /* fields */

    private static byte[] utilsClassBody = { // The .class file

    (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe,

    (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x2e,

    (byte) 0x00, (byte) 0x3d, (byte) 0x0a, (byte) 0x00,

    (byte) 0x11, (byte) 0x00, (byte) 0x1f, (byte) 0x07,

    (byte) 0x00, (byte) 0x20, (byte) 0x07, (byte) 0x00,

    (byte) 0x21, (byte) 0x0a, (byte) 0x00, (byte) 0x03,

    (byte) 0x00, (byte) 0x22, (byte) 0x0a, (byte) 0x00,

    (byte) 0x02, (byte) 0x00, (byte) 0x23, (byte) 0x0a,

    (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x24,

    (byte) 0x07, (byte) 0x00, (byte) 0x25, (byte) 0x07,

    (byte) 0x00, (byte) 0x26, (byte) 0x07, (byte) 0x00,

    (byte) 0x27, (byte) 0x0a, (byte) 0x00, (byte) 0x08,

    ...

    PBP의 IxcClassLoader 클래스


    이 코드를 보면utilsClassBody라는 byte[] 필드에 클래스 생성에 필요한 유틸리티 클래스의 바이트코드를 바이너리 형태로 넣어놨음을 알 수 있다. static 필드이므로 클래스 정적 초기화(static initialization)시에 해당 필드가초기화될 것이다. C/C++ 코드를 많이 작성해온 개발자라면 이런 형식의 배열 사용법에 익숙할 것이다. 자바에서 이런 배열초기화의 문제점은 무엇일까? 대답에 앞서서 이 클래스를 한 번 디컴파일해보자.


    static {};

    Code:

    0: sipush 1165

    3: newarray byte

    5: dup

    6: iconst_0

    7: bipush -54

    9: bastore

    10: dup

    11: iconst_1

    12: bipush -2

    14: bastore

    15: dup

    16: iconst_2

    17: bipush -70

    19: bastore

    20: dup

    21: iconst_3

    22: bipush -66

    24: bastore

    25: dup

    26: iconst_4

    27: iconst_0

    28: bastore

    29: dup

    ...

    PBP의 IxcClassLoader 클래스 디컴파일


    무엇이 문제인지 감이 잡히는가?지면 관계상 일부만 표시했지만, byte[] utilsClassBody는 길이가 1165이다. C/C++이였으면 이 데이터를곧바로 메모리에 로드하였겠지만, 자바의 클래스 로더는 그렇지 않다. 자바의 경우 클래스를 초기화할 때 1165 길이의byte[]를 힙에 생성하고 각 원소를 하나하나 초기화해주어야 한다. 이 초기화를 위해서 무려 7738개의 바이트코드가필요하다. 코드 길이도 문제지만, 클래스 로딩 시간 또한 무척 길어진다.

    자바의 원산지인 썬에서 배포하는 코드에서 이런 문제점이 있다는 점을 생각해보면 언뜻 비슷해 보이는 두 언어의 차이점을 정확히 알고 쓰는 일이 쉽지 않음을 알 수 있다.


    문자열 처리


    자바는 문자열의 편리한처리를 위해서 문자열 병합 연산자(+)를 제공한다. 따라서 우리는 "Hello" + "World"와 같이 문자열을 병합할 수있고, "I am " + name + "."과 같이 중간에 변수를 삽입해서 문자열을 생성할 수도 있다.

    하지만 자바의 String 클래스는변경 불가능(immutable)한 클래스이다. 따라서 한 번 문자열을 생성하면 문자열의 값을 바꾸는 것은 불가능하다. 따라서replace, replaceAll, toLowerCase 등의 메쏘드는 모두 기존의 문자열은 그대로 두고 새로운 문자열을리턴한다. java.lang.String의 API를 유심히 읽어본 개발자라면 정답을 알고 있을 것이다.


    ◆ java.lang.String API에서 발췌

    문자열 병합은StringBuilder(혹은 StringBuffer) 클래스의 append 메쏘드를 통해 이루어진다. 추가적인 정보를 위해서는자바 언어 명세서(Java Language Specification)을 참조하기 바란다.


    즉 우리가 String a = "Hello"; a += " World"; 라고 프로그램을 작성하더라도 실제 병합은 StringBuilder 클래스를 통해 이루어짐을 의미한다. 역시 실제 프로그램을 컴파일해서 확인해보도록 하자.


    public class Foo {

         public static void main(String args[]) {

             String h = "Hello";

             h += "World";

         }

    }

    <!--[if !supportEmptyParas]--> <!--[endif]-->

    public static void main(java.lang.String[]);

    Code:

    0: ldc #2; //String Hello

    2: astore_1

    3: new #3; //class java/lang/StringBuilder

    6: dup

    7: invokespecial #4; //Method java/lang/StringBuilder."<init>":()V

    10: aload_1

    11: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

    14: ldc #6; //String World

    16: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

    19: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;

    22: astore_1

    23: return

    String 병합


    바이트코드를 잘 모르더라도String 대신에 StringBuilder 클래스를 통해 문자열을 병합하고 이후에 toString 메쏘드를 이용해 문자열을돌려줌을 쉽게 유추해 볼 수 있다. 이처럼 javac은 자바 개발자가 알게 모르게 여러 가지 일을 해주고 있는데, 바꿔 말하면자바 개발자는 의도하지 않게 비효율적인 명령을 실행할 수도 있다는 뜻이다. 실제로 초창기 자바는 멀티 쓰레드 세이프한StringBuffer의 append 메쏘드를 이용했는데, append는 매번 락을 잡았다 풀었다 하였기 때문에 심각한 속도저하의 원인이 되기도 했었다.


    Inner Class


    이너 클래스가 있는 클래스를컴파일하면, $ 표시가 붙은 클래스 파일이 생성되는 것을 보았을 것이다. 그리고 JVM 명세서를 잘 읽어보면 이너 클래스라는 게존재하지 않는다는 사실도 알 수 있을 것이다. 그렇다면 다음과 같이 이너 클래스가 있는 클래스를 컴파일하면 어떤 일이 생기는걸까?


    public class Foo {

         static class Bar {

             private boolean flag = true;

         }

         public static void main(String args[]) {

             Bar bar = new Bar();

             System.out.println(bar.flag);

         }

    }

    Inner Class


    위 예제의 경우 Foo 내부에Bar라는 정적 이너 클래스를 선언하였다. Bar는 Foo의 이너 클래스이므로 private 멤버라도 직접 접근이 가능하다. 이클래스를 컴파일하면 Foo.class와 Foo$Bar.class라는 두 개의 클래스 파일이 나타난다. JVM에는 이너 클래스의개념이 없으므로, 자바 소스 코드 상에서는 Bar는 Foo의 이너 클래스이지만 바이트코드 상에서는 별도의 클래스가 되는 것이다.


    public class Foo extends java.lang.Object{

         public Foo();

         public static void main(java.lang.String[]);

    }

    <!--[if !supportEmptyParas]--> <!--[endif]-->

    class Foo$Bar extends java.lang.Object{

         Foo$Bar();

         static boolean access$000(Foo$Bar);

    }

    Inner Class 디컴파일


    또 하나 특이한 점으로는access$000라는 메쏘드가 있다. 원래 Bar 클래스에는 없는 메쏘드인데 어째서 바이트코드에는 나타난 것일까? 그 이유는자바 소스 코드에서는 Bar가 이너 클래스이므로 Foo의 main 메쏘드에서 Bar의 private field가 접근 가능해야하는데, 실제 바이트코드 상에서는 별도의 클래스이므로, private 멤버의 값을 읽을 수 없게 된다. 이 문제를 해결하기 위해자바 컴파일러는 access$000이라는 메쏘드를 생성해 Foo가 Bar의 필드 참조 시 access$000으로 대체하게 된다.



    Enumeration


    Java5에는 타입 세이프 enum 강화된 for 루프, 제네릭스(generics), 오토박싱(autoboxing),언박싱(unboxing), 가변인자(varargs), 정적 임포트(static import), 메타데이터(metadata) 등여러 가지 언어 기능이 추가 되었다. 하지만 언어만 바뀌었을 뿐 기존의 JVM이 사용하던 바이트코드에는 차이가 없다. 이 말은결국 이런 기능들은 전부 컴파일러가 해준다는 뜻이다. 타입 세이프 enum을 통해서 컴파일러가 어떤 바이트코드를 생성해 내는지살펴보자.


    public enum Week {

         MON, TUE, WED, THU, FRI, SAT, SUN

    }

    Week Enum


    위 Week enum은 월요일부터 일요일까지 각각의 요일을 나타낸다. enum이 없던 시절에는 어떻게 구현했을까? 한 가지 방법은 int 상수를 이용하는 것이다.


    public class Week {

         public static final int MON = 0;

         public static final int TUE = 1;

         public static final int WED = 2;

         public static final int THU = 3;

         public static final int FRI = 4;

         public static final int SAT = 5;

         public static final int SUN = 6;

    }

    <!--[if !supportEmptyParas]--> int 상수를 이용한 Week Class

    <!--[endif]-->


    이 방법도 동작에는 전혀문제가 없지만, MON, TUE, WED 같은 값들이 int이기 때문에 MON * 2 같이 의미 없는 연산을 하더라도 컴파일타임에 타입 에러를 발견할 수 없었다. 이런 문제를 해결하기 위해 타입 세이프 enum 패턴이 널리 쓰였다.


    public class Week {

         public static final Week MON = new Week();

         public static final Week TUE = new Week();

         public static final Week WED = new Week();

         public static final Week THU = new Week();

         public static final Week FRI = new Week();

         public static final Week SAT = new Week();

         public static final Week SUN = new Week();

    }

    타입 세이프 enum 패턴


    이 방식은 타입 세이프하지만 각필드가 오브젝트이므로 int를 사용한 방식과는 달리 switch 문에 사용이 불가능하다는 불편함이 있었다. 반면에 Java5에도입된 타입 세이프 enum은 타입 세이프하면서 switch 문에서도 사용이 가능하다. 어떻게 구현한 것일까? Weekenum을 디컴파일해보자.


    public final class Week extends java.lang.Enum{

    public static final Week MON;

    <!--[if !supportEmptyParas]--> <!--[endif]-->

    public static final Week TUE;

    <!--[if !supportEmptyParas]--> <!--[endif]-->

    public static final Week WED;

    <!--[if !supportEmptyParas]--> <!--[endif]-->

    public static final Week THU;

    <!--[if !supportEmptyParas]--> <!--[endif]-->

    public static final Week FRI;

    <!--[if !supportEmptyParas]--> <!--[endif]-->

    public static final Week SAT;

    <!--[if !supportEmptyParas]--> <!--[endif]-->

    public static final Week SUN;

    <!--[if !supportEmptyParas]--> <!--[endif]-->

    ...

    <!--[if !supportEmptyParas]--> <!--[endif]-->

    static {};

    Code:

    0: new #4; //class Week

    3: dup

    4: ldc #7; //String MON

    6: iconst_0

    7: invokespecial #8; //Method "<init>":(Ljava/lang/String;I)V

    10: putstatic #9; //Field MON:LWeek;

    ...

    타입 세이프 enum 패턴


    우리가 간단히 enum Week {MON, TUE, ... }로 써줬지만 실제로 컴파일하면 타입 세이프 enum 패턴처럼 각각이 public finalstatic Week 필드로 들어가 있음을 알 수 있다. 즉 우리가 타입 세이프 enum 패턴에서 수동으로 구현해주던 것을컴파일러가 대신해 주는 것이다. 클래스 초기화인 static{} 에서는 Week의 객체를 생성해서 각 필드를 초기화해주고 있다.객체를 생성할 때 MON은 0, TUE는 1, WED는 2 하는 식으로 값을 주고, switch 문에서는 이 값을 얻어오는ordinal() 메쏘드를 호출하여 switch 문에서도 사용할 수 있게 해준다.



    정리


    지금까지 자바컴파일러(javac)가 해주는 몇 가지 일을 살펴보았다. 특히 자바 소스 코드의 특정 구문이 어떤 바이트코드로 변환되는지를위주로 보았다. 우리는 javap를 이용해 결과를 살펴보았지만, JVM 지식이 있고 자바 언어 명세서를 꼼꼼히 읽은 개발자라면이미 알고 있었을 내용일지도 모르겠다.

    자바 개발자를 만나서 이야기해보면깜짝 놀라는 일 중에 하나는, 자바의 가장 근간이 되는 자바 언어 명세서(Java Language Specification)와자바 가상 머신(Java Virtual Machine) 명세서를 숙독한 개발자가 거의 없다는 점이다. 자바튜토리얼(tutorial)이나 여러 자바 입문서로 시작하여 단 한 번도 명세서를 보지 않고 지금까지 프로그램을 작성해 온개발자가 부지기수다.

    모든 자바 컴파일러, 자바 가상머신은 모두 이 명세서를 기준으로 만들어졌다. 썬에서 배포하는 레퍼런스 구현(reference implementation)도결국 이 명세서를 바탕으로 만든 구현 중 하나에 지나지 않는다. 즉 자바 언어 명세서는 자바 세상의 성경인 셈이다. 명세서를바탕으로 자바의 문법과 의미를 분명히 명확히 이해하고, 자바 코드가 어떤 바이트코드로 변환되는지를 숙지하는 것은 고급 개발자가되기 위해 반드시 필요한 일이다.

    이 과정에서 디컴파일러를 이용해의문을 해소하는 일은 무척 유용하다. 앞서 언급하지는 않았지만 try, finally 구문은 바이트코드로 어떻게 표현되는지,synchronized 블록은 바이트코드로 어떻게 변환되는지 등을 살펴보면 자바 언어와 JVM에 대한 이해를 넓힐 수 있다.자바의 경우 컴파일러에 대한 지식은 결국 언어 지식을 넓히는 길인 셈이다.




    [출처]

    http://skyul.tistory.com/334


    'Java' 카테고리의 다른 글

    자바 중복 제거  (0) 2010.03.04
    [자바] 현재 시간을 출력하는 함수  (0) 2010.03.03
    컬렉션  (0) 2010.02.12
    SSL 서버  (0) 2009.12.29
    [JAVA] 컴파일러 들여다보기  (0) 2009.12.24
    자바에서 구조체사용..  (0) 2009.12.23

    Comment +0


    자바에서는 구조체라는건 없습니다.

    C에서의 구조체가 어떻게 보면 전혀 필요 없는거거든요...

    왜냐면 자바는 객체지향언어이고...

    사용자정의 타입을 만드는게 바로 하나의 클래스는 만드는 것이기 때문이죠..


    예제)

    typedef struct _node
    {
    struct _node *next;
    int number;
    int weight;
    } node;


    자바에는

    class Node{
    int number = 0;
    int weight = 0;
    public void methodA(){}

    }

    'Java' 카테고리의 다른 글

    자바 중복 제거  (0) 2010.03.04
    [자바] 현재 시간을 출력하는 함수  (0) 2010.03.03
    컬렉션  (0) 2010.02.12
    SSL 서버  (0) 2009.12.29
    [JAVA] 컴파일러 들여다보기  (0) 2009.12.24
    자바에서 구조체사용..  (0) 2009.12.23

    Comment +0