내용에 대해서 책임지지 않습니다. ㅋㅋ


Unicode provides a unique number for every character,
no matter what the platform,
no matter what the program,
no matter what the language.

http://www.unicode.org/standard/WhatIsUnicode.html


위에 설명되어 있는대로다.




유니코드란?

unicode는 모든 문자에 index를 줘 놓은 것이다. 더 이상도 아니고, 더 이하도 아니다.
이 index를 code point라고 부르는데, 그냥 index라고 칭하도록 하자.

'A'라는 글자는 0x0041 이라는 index를 가진다.
'a'라는 글자는 0x0061 이라는 index를 가진다.
'가'라는 글자는 0xac00 이라는 index를 가진다.
( 더 많은 글자와 index를 보려면 http://www.unicode.org/charts/ 를 참고하자 )




표현방법

저렇게 정해져 있는 index를 표시하는 방법에는 UTF와 UCS두가지 종류가 있다.
( UTF - Unicode Transformation Format ,    UCS - Universal Character Set )

UCS
UCS는 몇바이트로 index를 표현할 수 있느냐를 나타낸다.
즉 UCS-2는 2byte로 index를 나타낼꺼고 UCS-4는 4byte를 이용해서 index를 나타낼거라는거다.

UTF
UTF는 몇 비트단위로사용해서 index를 나타낼것인가를 말한다.
UTF-8은 8bit씩 늘려가며 index를 나타낼꺼라는거고,
UTF-16은 16bit씩 index를 나타낼꺼고, UTF-32는 32bit씩 index를 나타낼꺼라는거다.
( 실상 UTF-16과 UCS-2는 같다고 볼 수 있다. 마찬가지로 UTF-32와 UCS-4도 마찬가지다.  하지만 unicode 3.1에 오면서 달라 졌다. )





UTF-16

원래 처음에 unicode의 index는 2byte로 나타낼 수 있었다.
그랬는데, unicode 가 버젼업되어 4.0이 나왔을때에는 0x10FFFF 까지의 index가 생겼다.

처음에는 UTF-16으로 모든 문자를 나타낼 수 있었으나,
( 2byte로 표현할 수 있는 index를 가진 문자 목록을 BMP Basic Multilingual Plane 라고 부른다. )
유니코드 4.0이 나오면서, 2byte로는 0x10FFFF 같은 값을 가리킬 수 없게 되었다.

그래서 UTF-16으로는 BMP에 있는 문자들은 2byte로 처리하고, 
BMP보다 더 높은 index를 가지는 놈들은 4byte로 처리 한다.
문자 index 0x0000 부터 0xFFFF 까지는 2byte로 처리 하고
문자 index 0x10000 부터 0x1FFFF 까지는 4byte로 처리 된다.





UTF-32

UTF-32는 기본적으로 4byte를 사용하기 때문에, 위와 같은 짓을 하지 않아도 된다.





UTF-8

영어권에 있는 사람들은 UTF-16을 쓰면 손해다.
모든 영어는 1byte만 있으면 256개를 표현할 수 있으므로, 모든 문자를 넣을 수 있기 때문이다.

그래서 나온게 UTF-8이다.
영어권은 1byte로 표현하고, 그것보다 높은 index를 가지는것은 2byte 혹은 3byte 혹은 4byte ..
요렇게 늘려 가면서 쓰도록 되어 있다.





서로간의 변환

UTF-8, UTF-16, UTF-32, UCS-2, UCS-4 는
모두 unicode의 문자 index를 나타내기 위한 방법이기 때문에,
서로간의 변환은 당연히 잘 된다. ( UCS-2는 한계를 가지고 있다. )




글자처리

우리가 글자 "가"를 쓴다고 해 보자.  글자 "가"는 1글자이다.
그러므로 "가"를 나타내는 index가 있다. 물론 "나"를 나타내는 index도 있다.

한글로 표현할 수 있는 글자는 매우 많다.
그 많은 글자 모두에게 index를 줄 수가 없다.

현재 사용하고 있는 모든 글자에 index를 준다고 해도,
시간이 지나서 새로운 글자가 추가 되어 index가 모자르게 된다면 어떻게 할것인가?

그래서 유니코드는 완전한 글자를 제공해 주기도 하지만,
글자를 조립할 수 있도록 조립가능한 글자를 제공해 준다.

다시 "가"를 쓴다고 해 보다.
"가"라는 글자는 1개이지만, 실제로는 초성 "ㄱ"과 중성"ㅏ" 가 합쳐져서 만들어진 글자이다.

그러므로 "가"를 표현하는 방법은 완성된 글자 "가"0xAC00가 될 수도 있고,
초성"ㄱ"과 중성"ㅏ"를 조립한 "가"0x1100,0x1161 로 나타낼 수도 있다.
( 초성 "ㄱ"은 0x1100 - HANGUL CHOSEONG KIYEOK )
( 중성 "ㅏ"는 0x1161 - HANGUL JUNGSEON A )

이를 조합할 수 있게 해 주는 index는 1100 부터 있다.
( Hangul Jamo - Korean combining alphabet - http://www.unicode.org/charts/PDF/U1100.pdf )


이는 비단 한글뿐만 아니라,
일본어 역시 완성된 글자가 있기도 하고, 조합할 수 있게도 되어 있다.

영어 역시 그렇다. 영어에서 무슨 글자를 조합하냐 라고 말하겠지만, 
이력서를 나타내는 Resume 의 경우에는 e 와 ' 의 조합으로 이루어 질 수도 있다.


  1. 지민아빠 2008.02.28 09:47 신고

    맞는 말이구만 왜 내용에 책임을 안져요! ㅋㅋ

    • Chan 2008.02.28 09:59 신고

      유니코드랑 UTF관련은 머릿속에 정리 된것을 열심히 읽었는데,
      그 뒤에 글인 CP949 관련 글은 아직 머릿속에 확립이 안되어서.. ㅋㅋㅋ.
      CP949에 "책임질수 없음" 넣어 놓고, 유니코드 글에도 걍 넣었어요.. ㅋㅋ

    • 지민아빠 2008.03.11 12:05 신고

      아참. 펄에서 사용되는 이름이랑 자바에서 사용되는 이름이랑 약간 달라요. CP949, MS949, EUC-KR 의미가 약간 다름.

  2. sanaigon 2009.01.09 09:49 신고

    퍼가용ㅋ

  3. finebe 2009.04.24 14:11 신고

    퍼가요~^^; 공개글로 원치않으시면 말씀해주세요

    • Chan 2009.04.24 18:53 신고

      출처만 밝힌다면 상관없습니다. ㅋㅋ

  4. 2009.07.24 15:40

    비밀댓글입니다

  5. 킴킴 2014.01.20 17:13 신고

    퍼갈게요 ㅎㅎ

  6. carrot1st 2015.07.27 10:39 신고

    퍼갑니다 잘보겠습니다~

  7. 어벙이 2015.08.17 12:41 신고

    퍼갈게요..~~ ^^ 좋은 내용 잘 보고 갑니다..

  8. 라면사리누구야!! 2016.07.28 09:33 신고

    잘보고 갑니다~
    퍼갈게요~~ ^^;

  9. 뚝딱콩망치 2017.03.26 16:51 신고

    내용 참고해서 글써두 될까요 ㅠㅠ 출처는 꼭 남기겠습니다!

웹서비스

기본 개념

  • 네트워크 상의 접근 가능한 소프트웨어의 기능단위
  • 플랫폼, 프로그래밍 언어, 컴포넌트 모델에 독립적인 기술
  • SOA ( Service-Oriented Architecture ) 기반
    • SOA에서는 소프트웨어의 기능이 서비스의 집합으로 분류된다. 
  • SOA의 메카니즘 
    • Service provider : 어떤 동작을 기술(description) 하고 이를 Registry 에 등록( publish ) 한다.
    • Service registry : provider를 등록하고, consumer에게 provider의 정보를 제공한다.
    • Service comsumer : registry에서 provider정보를 찾아 ( find ) , provider를 연결(bind) 한다.

Web Service Stack

  •  Web service stack - 특정 플랫폼이나 제조사에 의존적이지 않음 ( platform- and vender-netural )
  • Stack 구조
    • Service publication Discovery : UDDI
    • Service Description : WSDL
    • XML Messaging : SOAP
    • Transport network : http, smtp, ftp, https over tcp/ip
  • Stack에 대한 설명 
    • UDDI : Universal Description and Discovery Interface : 웹 서비스를 공개하고 탐색하는 표준 메카니즘
    • WSDL : Web Service Descritpion Language : 웹 서비스를 기술하는 표준 메카니즘
    • SOAP : Simple Object Access Protocol : 웹 서비스를 호출하는 표준 메카니즘


Web Service Call ( XML RPC , SOAP )

XML-RPC

  1. RPC - Remote Procedure Call - 원격지의 메소드를 호출 한다.
  2. XML RPC - XML을 이용해서 원격지의 메소드를 호출한다.
  3.  특징
    1. XML 사용
    2. Http를 사용

SOAP

  • 기본적으로는 RPC 와 같음
  • Http 이외의 다른 전송 프로토콜 지원
  • 복잡한 Data Type 지원
  • 메세지의 처리 방법을 기술
  • 응답은 HTTP 방식을 이용
    • 200일 경우에는 Content-Type 이 XML 형태이나
    • 500일 경우에는 text/html 형태로 들어올 수 있다.
  • SOAP의 호출 동작 
    •  SOAP Client  <->  Web Server <-> SOAP Server <-> Web Service


WSDL

  • WSDL : Web Service Descritpion Language
  • 웹 서비스를 기술 ( 표현, 설명 ) 한다. 
    • 웹서비스가 하는 일
    • 호출 가능한 메소드
    • 전달해야 하는 파라미터
    • 파라미터의 Type
    • 사용하는 바인딩 프로토콜
  • 즉, WSDL 문서가 있다면 웹서비스의 기능을 호출할 수 있다.
  • WSDL 문서의 구조 
    • Implementation Specific 
      • Service : 특정 바인딩을 어떠한 Port ( 주소 ) 로 연결할것인가?
      • Port : 웹 서비스로 접근 가능한 주소 ( End-point? )
    • Abstract Definition 
      • Binding : 사용될 전송 프로토콜 ( Port type에서 사용할 프로토콜 - SOAP ) , 요청방식 ( rpc , document )
      • Port Type : 공개된 ( 호출할 수 있는 ) 메소드 집합.
      • Message : 메소드에서 사용할 파라미터
      • Types : Data Type ( integer , float, String ... )


UDDI

  •  UDDI : Universal Description and Discovery Interface 
  • 웹 서비스 제공자와 클라이언트들이 함께 사용할 수 있는 중앙 저장소 제공  
    • 클라이언트가 필요한 웹 서비스를 찾아 내 줄 수 있게 해야 함.
    • 웹서비스 제공자가 서비스를 공개할 방법이 필요 

이 글은 스프링노트에서 작성되었습니다.

java.lang.Character

  • JDK 1.4 : Character information is based on the Unicode Standard, version 3.0.
  • JDK 5.0 : Character information is based on the Unicode Standard, version 4.0. 

Java에서 char 은 16bit 고정 길이를 가지도록 되어 있다.

하지만 unicode 의 값 중에는 U+0000 ~ U+FFFF 를 넘어서는 값도 있기 때문에 이에 대한 처리가 문제가 된다.

1

JDK 1.4의 api document 중에서 Character 에 관한 문서를 확인해 보고

( http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Character.html  )

JDK 5.0의 api document 중에서 Character 에 관한 문서를 확인해 보면 서로 틀린것을 알 수 있다.

( http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Character.html )



JDK 5.0에서는 Unicode Character Representations 항목이 추가 된 것을 알 수 있다.

  1. 유니코드의 표준이 16비트 이상도 표현하도록 변경되었다.
  2. 현재는 U+0000 부터 U+10FFFF 까지 정의되어 있다.
  3. U+0000 부터 U+FFFF 까지는 Basic Multiingual Plane(BMP)를 참고한다.
  4. U+FFFF 보다 큰것들은 supplementary cahcaters가 있어야 한다.
  5. Java 2 에서는 UTF-16을 사용한다.
  6. supplementary chacters는 char 두개로 이루어 진다.
  7. 첫번째 char은 U+D800 ~ UDBFF를 , 두번째 char은 U+DC00~U+DFFF 까지의 범위를 가진다.
  8. char은 BMP나 UTF-16인코딩만을 가리킬 수 있다. 
    1. 그러므로 char를 사용하는 메소드를 쓸때에는, supplementary char에 대해서는 메소드를 호출 하면 잘못된 값이 나올 수 있다.
    2. 예)  Character.isLetter('\uD840') 를 사용하면 false로 return 된다.
  9. int는 supplementary code point 도 가리킬 수 있다. 
    1. 하위 21bit 는 Unicode값을 가리키고, 상위 11비트는 항상 0로 채워져 있다.
    2. 21bit인 이유는 현재 Unicode 가  U+10FFFF 까지 가리킬 수 있기 때문이다. ( U+10FFFF를 2진수로 변경하면 총 21bit 만을 차지하게 된다. )
    3.  그러므로 int를 사용하는 char 관련 메소드를 사용할때에는 supplementary char에 대해서는 제대로 된 응답이 반환된다.
      1. 예)  Character.isLetter(0x2F81A) 를 사용하면 true로 return 된다.

FileSystem에서 File의 lastModifiedTime 에 관하여...

자바에서는 화일을 다룰 수 있는 File 라는 클래스를 제공한다. ( java.io.File )

이 클래스에서는 화일의 정보를 get 하거나 set 할 수 있도록 제공해 주는데.

그중에서 지금 확인해 볼 것은 lastModified Time 에 관한 내용이다.

 

 자바의 File 에서는 해당 화일의 마지막 변경 시간을 얻어 올 수도 있으며, 지정해 줄 수 있는 메소드를 제공해 준다.

 java.setlastmodified.gif

 

 그리고 위의 코드는 OS에 맞는 FileSystem의 setLastModified를 호출하게 되며, Windows에서는 일반적으로 Win32FileSystem.setLastModified를 호출하게 된다.

 Win32FileSystem.setlastmodi.gif

 

이 놈은  결국은 native 코드를 사용호출 하게 된다. 이에 대한 native 코드는 아래와 같이 이루어져 있다.

 native.setlastmodified.gif

 

그래서 결국은 windows api에서 제공하는 SetFileTime 이라는 함수를 호출하게 되어 있다.

이것에 대한 msdn 내용을 살펴 보면 아래와 같이 되어 있다.

 msdn.setFileTime.gif

 

파일 시스템 마다 다르게 동작할 수 있단다.

FAT 에서는 만든 시간은 10밀리초 까지 해상도를 제공하고,

수정한 시간은 2초의 해상도를 제공하고,

접근한 날자는 하루 단위로 제공한다고 한다.

 

아래는 FAT 에 관한 표 중 일부분이다.

 FAT32.gif

 

그렇기 때문에 해당 File 객체를 만들어서 setLastModified()를 수행 한다고 해서,

모든 시스템에서 정해진 시간으로 저장 되는것이 아닐 수도 있다.

 

이 글은 스프링노트에서 작성되었습니다.

  1. 박서은 2007.07.07 00:18 신고

    그랬군요. 그런거였군요.

    • Chan 2007.07.08 16:33 신고

      ㅎㅎ 네~ ㅎㅎ ;;;;; 그런거였답니다. ㅎㅎ

다음의 내용을 가지고 테스트를 해 보자.

  1. public class A {
  2.     public String getString() {
  3.         return "call A.getString() Method";
  4.     }
  5. }

  1. public class B extends A {
  2.     public String getString() {
  3.         return "call B.getString() Method";
  4.     }
  5. }

  1. public class C {
  2.     public static void main(String... strs) {
  3.         B b = new B();
  4.         System.out.println ( b.getString() ) ;
  5.     }
  6. }


이렇게 만든 상태에서 모두 컴파일을 하고, C 화일을 실행 시키면  "call B.getString() Method" 가 나온다.


 그 후에 B.java 화일은 그대로 두고 A 클래스에 메소드를 하나 추가 하여 다시 작성하자.

  1. public class A {
  2.     public String getString() {
  3.         return "call A.getString() Method";
  4.     }
  5.     // 아래의 메소드를 추가 한다.
  6.     public String getString2() {

            return "call A.getString2() Method";

        }  

  7. }


그리고 C 화일을 수행 부분인 main 메소드를 다음과 같이 변경 시킨다.

  1. public class C {
  2.     public static void main(String... strs) {
  3.         B b = new B();
  4.         System.out.println( b.getString2() );
  5.     }
  6. }


그리고 A 와 C 만을 컴파일 하고 ( B 는 꼭 그대로 둔다. ), C 클래스를 수행하면 어떤 결과가 날까?

( B class 는 아직까지 컴파일 되지 않았고, B의 부모인 A 만 새로운 메소드를 추가 하고 새롭게 컴파일 되었다. )


결과는 다음과 같다. call A.getString2() Method


B클래스는 전혀 새롭게 컴파일 하지 않았는데, 어떻게 A클래스에 있는 메소드를 알아서 호출해 주는것일까?


물론 저렇게 만들지 않으면 정말로 불편하게 된다. 상위클래스에서 자식으로 넘겨 줄 수 있는 제한자를 가지고 있는 것들을 추가 할때마다 자식클래스들도 모두 다시 컴파일 해야 한다면 얼마나 큰 낭비인가? 하지만 그렇게 상식적으로 생각하지 말자. 잘못된 상식은 수두룩하니깐.


그렇게 해서 내가 테스트 해 본 방법은 다음과 같다.


  • 직접 수행 해 보기. - 이미 위의 방법을 통해서 확인해 보았다.
  • 원래의 B.class 화일과 새롭게 컴파일 된 B.class 화일을 바이너리 비교
    • 비교해 보았으나 두개의 바이너리 내용이 똑 같음.


이렇게 한다고 해도, 이것은 테스트 밖에 되지 않는다. 우연찮게 두개의 메소드 테이블이 같아서 똑같은 바이너라가 나올 수도 있다고 생각 할 수도 있다. 그러므로 좀 더 정확한 답을 찾아 보도록 하자.


.class 화일 Format 를 직접 찾아 보자.

 The class File Format : http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html


 class 화일은 다음과 같은 구조로 이루어져 있다.

    ClassFile {
     u4 magic;
     u2 minor_version;
     u2 major_version;
     u2 constant_pool_count;
     cp_info constant_pool[constant_pool_count-1];
     u2 access_flags;
     u2 this_class;
     u2 super_class;
     u2 interfaces_count;
     u2 interfaces[interfaces_count];
     u2 fields_count;
     field_info fields[fields_count];
    u2 methods_count;
   
method_info methods[methods_count];
     u2 attributes_count;
     attribute_info attributes[attributes_count];
    }


그 중에서 우리가 관심이 있는 부분은 메소드이고, 그것과 관련 있는 부분은 아래의 두개이다.

u2 method_count;

method_info methods[methods_count];


우선 method_count 에 대한 설명을 보자.

methods_count
The value of the methods_count item gives the number of method_info structures in the methods table.

methods_count 는 methods 테이블에 있는 method_info 갯수란다. - 별로 중요하지 않군. 흠.


methods[]
Each value in the methods table must be a method_info (§4.6) structure giving a complete description of a method in this class or interface. If the method is not native or abstract, the Java virtual machine instructions implementing the method are also supplied.

The method_info structures represent all methods declared by this class or interface type, including instance methods, class (static) methods, instance initialization methods (§3.9), and any class or interface initialization method (§3.9). The methods table does not include items representing methods that are inherited from superclasses or superinterfaces.


우리가 원하는 내용을 찾아 버렸다. .class 화일에서는 methods[] 이 있고, 이 안에는 method_info가 들어 있는데, 이 method_info에는, 현재 클래스나 인터페이스에서 선언된 모든 메소드들이 들어 있다고 한다. 즉, 부모에 선언되어 있거나 하는 메소드들은 현재의 .class 화일에서 가지고 있지 않다는 말이 된다.


== 추가한 부분 ==
B.class 화일에서는 자기에게서 선언되지 않은, getString2() 라는 메소드 정보를 class 화일 안에 가지고 있지 않다.
( 왜냐하면 위에서 말했다 시피 .class 화일 안에는 자신에게서 선언된 메소드 정보만을 가지고 있어야 하기 때문이다. )

C 클래스에서 B 객체의 getString2() 메소드를 호출하게 되면,
B 객체에서는 자신의 메소드테이블을 검색해서 getString2() 가 있는지 확인하게 된다.

하지만 B 객체에서는 getString2() 이라는 메소드가 존재하지 않기 때문에,
부모인 A 객체에게 getString2() 을 요청하게 될 것이다.

자식 클래스인 B에서 선언되지 않았지만, 부모 클래스인 A 에서 메소드를 추가하여도,
C 클래스에서 A에서만 추가된 메소드를 B 에게 호출 하여도 문제가 없게 된다.

즉, B 클래스는 전혀 수정없이 확장성 있게 코드를 작성할 수 있게 된다.



그렇기 때문에,  위의 예에서 B.java 화일은 새롭게 컴파일 하지 않아도 정상적으로 동작하는게 옳다는 결론이 나온다.

일을 하다가 발견한 문제이다.

특정한 동작을 하는것이 있었는데..
이 놈이 유독스럽게 Mac 에서만 무진장 오래 걸린다는 문제 였다.

윈도우에서는 단 1초도 안되어서 끝나는 작업이었지만,
Mac 에서만 22초가 소요되고 있었다.

문제가 어디서 발생하는지는 찾았는데,
왜 Mac 에서만 유독 느린지 이유를 밝혀 내지는 못했다.


여하튼, 문제는 ArrayList의 removeAll 메소드에 있었다.
removeAll 메소드에 대해서 좀 살펴 보자.



ArrayList 의 상속 관계를 보면 아래와 같다.

사용자 삽입 이미지



여기서 removeAll 이라는 메소드는 Collection 에서 interface를 제공하고 있으며,
실제 그 구현은 AbstractCollection 에 아래와 같이 되어 있다.

사용자 삽입 이미지


보다시피 현재의 컬렉션에서 param 으로 들어온 컬렉션에 있는 item들을 모두 지우기 위해서
iterator 를 구하고, next를 하나꺼내와서
param으로 들어온 c 에 이미 들어 있는지 확인을 하고,
들어 있다면 지워주는 형태로 되어 있다.


여기서 다시 "c에 이미 들어 있는지 확인하는 c.contains( .. ) 의 코드는
indexOf(Object)가 0 보다 큰지 확인하게 된다.
이때 ArrayList의 indexOf(Object) 는 아래와 같이 구현되어 있다.

사용자 삽입 이미지

열심히 이미 가지고 있는 배열에서 루프를 돌면서 같은 놈이 있는지 확인을 한다.
물론 이 놈들이 Object 형태를 비교해야 하기 때문에 equals() 메소드를 사용하여서
비교를 한다.


그렇다면 내가 원래 있던 20개의 Collection 에서
10개의 데이터를 removeAll 한다고 해 보자.

1. AbstractCollection의 removeAll을 호출한다.
2. 20개에 대해서 iterator 를 구해서 20번 루프를 돌아야 한다.
2.1. 현재 선택되어 있는 아이템이 10개에 포함되어 있는지 확인해야 한다.
2.2. 이것을 확인하기 위해서는 indexOf() 를 수행해야 한다.
2.3. indexOf 내부에서는 10개에 대해서 루프를 돌아야 한다.
2.4. Object 비교이기 때문에 equals 를 수행하기 위해서 내부적인 연산을 해야 한다.


중요한것은 전체 배열에 대해서 이중 for loop 를 돌아서 처리 한다는것이다.




그렇다면 이 loop를 좀 더 덜 돌릴 수 있는 방향이 없을까?
항상 cpu 와 memory 사이에는 trade-off 가 있다.
물론 지금 이야기 하고자 하는 방법은 memory 측면에서는 손해 볼 수 있다.




내가 그래서 선택한 방법은 HashMap을 사용하는 방법이다.
안타깝게도 HashMap 에서는 removeAll 같은 메소드를 제공해주지 않기 때문에.
직접 for 루프를 돌아 가면서 데이터를 지워주어야 하는 귀찮은 점은 있다.

HashMap의 remove(Object) 코드는 아래와 같이 구성되어 있다.

사용자 삽입 이미지


remove(Object)를 수행하게 되면 removeEntryForKey(Object)를 수행하게 된다.

이때 removeEntryForKey(Object) 에서는
param으로 들어온 key에 대해서 hashCode() 를 구하고,
전체 배열 중에서 구해진 hash와 같은 값을 가지는 위치만을 비교 하게 된다.


그렇다면 HaspMap 에서 데이터를 지우는 순서를 보자.

1. removeAll이 없기 때문에 어쩔 수 없이 외부에서 for를 돌려서 remove 를 여러번 시켜 준다.
2. hashCode() 값을 구하고, hash 같은 배열 부분만을 검색한다.
3. equals()를 호출하여 비교하면서 처리 한다.

여기서도 사용자가 for를 외부에서 돌려 주고,
내부에서도 while loop를 도는 2중 loop 구조이기는 하지만,
hash 가 같은것만 돈다는것이 핵심이다.


이 결과는 equals()과 hashCode()를 구현하는 방식에 따라서 다른 결과를 도출할 수도 있다.



약 400개의 데이터에 대한 작업이었는데
ArrayList.removeAll()에서는 22 초가 걸렸었고,
HashMap.remove() + for 로 수정한 뒤에는 0.5 초대의 시간이 걸렸다.


이 결과는 Mac 에서만 유용할 수도 있다. 실제 윈도우에서도 약간 더 빨리 동작하기는 했다.
시간 날때  똑같은 코드가 왜 Mac 에서만 이렇게 느리게 동작하는가에 대한 조사를 해 보아야 겠다.


대학교 자료구조 수업 시간에 자주 등장하는 내용이지만,
실제로 이렇게 -_- 겁나게 차이를 느껴 보기는 처음이었다. -_-;


대학교때 공부 잘했던 사람들이 나와서도 잘 사는 이유가 있나 보다. ㅋㅋ
  1. 유야 2007.06.10 00:30 신고

    역시 난 제대로 디버깅한거였어!!!!
    Font의 canDiaplay도 무쟈게 느리더만 -_-

    • Chan 2007.06.10 01:18 신고

      대단해. ㅋㅋ.
      근데 -_- 왜 느릴까 -_-? 쩝쩝쩝..

  2. 옷장수 2007.06.10 12:55 신고

    Font의 canDisplay()가 느린이유는 char를 glyph으로 변환하는 과정을 거치기 때문이 아닐런지..

    • Chan 2007.06.10 21:27 신고

      ㅇㅎㅎ ;; 뭔 말인지 몰겠따.. ㅎㅎ ;;;

  3. 유겸애비 2007.06.11 11:40 신고

    이거 맥하고 상관이 없는글이자나욧!!
    글구 canDisplay()는 글립으로 만들지 않고 그냥 폰트에 어떤 문자가 정의되어있는지를 보는것일듯 싶네요

    • Chan 2007.06.11 18:17 신고

      수정했습니다. ㅋㅋ;;
      그리고 ;; 또 어려운 말들을 하시는군요.;; ㅎㅎ ;;

    • 옷장수 2007.06.12 09:39 신고

      오랜만에 보는거라서 소스를 봤었는데 canDisplay가 호출되면 CharToGlyphMapper라는 놈을 찾아서 여기에서 glyph이 보여질 수 있는지를 체크하던데요.

  4. 유겸애비 2007.06.12 19:16 신고

    Re:옷장수// Font란 char to glyph의 map이라고 추상화 시킬수 있는데 key가 정의되어있난 보는거지 char에서 glyph으로 변환을 시키는건 아닐껍니다.

    • Chan 2007.06.12 23:36 신고

      심도 있는 댓글이군요~ ㅋ
      찾아봐야 겠당~ ㅋㅋ

    • 옷장수 2007.06.14 14:03 신고

      음.. char를 glyph으로 변환한다는게.. char 값을 glyph의 index 값으로 변환한다는 의미였는데요.

오랜만에 공부하는 포스팅 ㅎㅎ..

Windows에서 Java의 FileOutputStream을 사용하게 되면,
다음과 같은 네이티브 코드를 사용하게 된다.


void
fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags)
{
  DWORD access = 0;
  DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
  DWORD disposition = OPEN_EXISTING;
  DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
  HANDLE h = NULL;
  int pathlen = 0;

  /* Note: O_TRUNC overrides O_CREAT */
  if (flags & O_TRUNC)        {    disposition = CREATE_ALWAYS;     }
  else if (flags & O_CREAT) {    disposition = OPEN_ALWAYS;         }

  if (flags & O_SYNC) {    flagsAndAttributes = FILE_FLAG_WRITE_THROUGH;    }

  if (flags & O_DSYNC) {  flagsAndAttributes = FILE_FLAG_WRITE_THROUGH;    }

  if (flags & O_RDONLY) { access = GENERIC_READ;   }

  if (flags & O_WRONLY) { access = GENERIC_WRITE;  }

  if (flags & O_RDWR)     { access = GENERIC_READ | GENERIC_WRITE;   }

  if (flags == 0)              {  access = GENERIC_READ;  }

  if (onNT) {
       WCHAR *pathbuf = pathToNTPath(env, path, JNI_TRUE);
       if (pathbuf == NULL) {
              /* Exception already pending */
             return;
       }

       h = CreateFileW(
           pathbuf,   /* Wide char path name */
           access,    /* Combine read and/or write permission */
           sharing,   /* File sharing flags */
           NULL,      /* Security attributes */
           disposition,         /* creation disposition */
           flagsAndAttributes,  /* flags and attributes */
           NULL);

       free(pathbuf);

  } else {

       WITH_PLATFORM_STRING(env, path, _ps) {
             h = CreateFile(_ps, access, sharing, NULL, disposition,
                                   flagsAndAttributes, NULL);
       } END_PLATFORM_STRING(env, _ps);
}

if (h == INVALID_HANDLE_VALUE) {
       int error = GetLastError();
       if (error == ERROR_TOO_MANY_OPEN_FILES) {
             JNU_ThrowByName(env, JNU_JAVAIOPKG "IOException",
                               "Too many open files");
            return;
       }
       throwFileNotFoundException(env, path);
       return;
  }
  SET_FD(this, (jlong)h, fid);
}


위의 코드는 그리 어렵지 않다. 각 속성을 조합한 뒤에 결국
Windows 에서 제공해주는 API인 CreateFile을 호출하게 된다.


하지만 이 옵션들 중에서 조정이 불가능한 옵션이 있으니. 이 옵션은.

  DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;

이다.


이 공유 속성은 내가 지금 쓰려고 하는 화일을
다른 프로세스에서 접근하면 어떤 동작이 가능하게 할것인가를 나타내주는 속성이다.


자바에서는 FileOutputStream을 만들거나 혹은  RandomAccessFile을 생성하게 되면,
fileOpen(...) 함수를 사용하게 된다.
결국 createFile을 쓰게 되는데, 이때 다른곳에서 접근하는 화일들에게도 쓰기 권한을 준 상태로 핸들을 만들게 된다.


그러므로, 자바에서 FileOutputStream을 만들고, 쓰고 있는 도중에,
다른 프로그램에서 해당 화일에 대해서 쓰기 권한을 가지고 화일을 열게 되면..
(  DWORD access = GENERIC_WRITE; )
화일이 깨질 수 있는 문제가 언제든지 발생할 수 있다.


그러므로 FileOutputStream을 사용하여 화일을 쓸려고 할때에는,
되도록이면 Channel을 구한뒤에 lock()을 건 뒤에 사용해주는것이 좋다.



자바에서는  shared Lock 과 exclusive Lock을 제공하는데
( 정확하게 이야기 하면 os 에서 제공하는것이지만 ),


자바에서 exclusive Lock를 잡고 있다면,

다른 프로세스에서 CreateFile을 사용할때 공유 속성에 WRITE가 없다면
핸들을 만드는것 조차 실패한다.

공유속성에 WRITE가 있으면 핸들을 만드는것은 성공한다.
하지만 exclusive Lock를 잡고 있기 때문에 WriteFile(..)등의 함수를 사용하여
화일에 데이터를 쓰려고 하면 실패하게 된다.



자바에서 shared Lock를 잡았을때에도
다른 프로세스에서 해당 화일에 데이터를 쓸려고 열어도
(  DWORD access = GENERIC_WRITE; )
화일 핸들은 잘 만들어지나 WriteFile 에서 데이터를 쓰려고 할때 실패하게 된다.



그러므로, 화일을 쓸때에는 lock를 잡고 쓰는것이 매우 안전하다고 볼 수 있다.


  1. 유야 2007.01.12 10:04 신고

    내가 광고 클릭해줬으니까 돈벌어서 맛난거사주삼 ㅋㅋ

    • Chan 2007.01.12 10:14 신고

      ㅎㅎ 감사 하삼. 자네가 첫번째 클릭자일세. ㅋㅋ

  2. 타오 2007.01.12 11:10 신고

    오홍~ 오홍~ +_+

  3. 유겸애비 2007.01.14 16:36 신고

    저도 클릭했어여. 이제 좀 쉬고 싶네요^^

이전에 적은 글이.

클래스와 객체의 차이에 대해서 이야기를 했었군요..
( 참고 : [PP/초보용] 클래스? 객체? 아니 이게 도대체 뭔가? )

오늘 마침 "인간의 본질에 관한 일곱가지 이론"이라는 책을 보았다.
( "인간 본질에 관한 일곱가지 이론" 레즐리 스티븐슨, 임철규 옮김, 종로서적 ,1981년 )
( 진주 내려 갔을때, 서점에 들렀다가 천원에 팔길래 -_- 낼름 집어 왔다. -_- )
( 아주 가끔씩 내가미쳤지라 생각하며 이런 글들도 읽어 주어야 한다. ㅎㅎ )

읽던중 플라톤이 말하는 "고양이" 라는것에 대한 이야기가 나왔고,
인터넷에 검색해 적당한 문구가 있어서 이렇게 옮겨 놓습니다.

출처 : http://cafe.naver.com/marxstudy/225 ( 문제가 된다면 삭제 하도록 하겠습니다. )


이하는 위의 글중에 일부를 인용한것입니다.

========================================================

플라톤의 철학사상 2 - 이데아론
문국진(저술활동가)

... 생략 ...




  1) 플라톤의 인식론


  ① 인식론 1 - 현상과 이데아적 실재

 

  플라톤에 따르면 우리가 평상시 접하는  감성적 사물들은 다만 현상이지 실재가 아니라 한다. 그의 철학은 흔히  이데아 철학이라 불리우는데 그것은 실재와 현상 간의 구별에 기초하고 있다. 이데아, 즉 형상에 대한 그의 설명을 직접 들어보자(이하는 러셀의 {서양철학사}에서 인용).



  우리가 "이것은 고양이다"하는 식으로 말할 수  있는 많은 동물들이 있다. 이 경우에 이 "고양이"라는 말은 무엇을 뜻하는가? 이것은 분명히 개개의 고양이와는 다른 것을 의미한다.

어떤 한 마리의 동물이 고양이로 불리는 것은,

모든 고양이에게 공통된 어떤 일반적인 성질을 갖고 있기 때문일 것이다.

그것은 이 고양이나 저 고양이가 아닌 무엇, 즉 어떤  "보편적인 고양이"를 뜻할 것이다.

이 보편적인 어떤 것은 특수한 고양이가 생겼다고  해서 생기는 것이 아니고, 죽었다고 해서 죽는 것이 아니다. 그것은 실제로 공간이나 시간의 어느 부분도 차지하고 있지 않다. 그것은 영원하다.

한편  개개의 고양이들은 이 "보편적인 고양이"의 성질을 다소 불완전하게 분유(分有)하여 고양이가 되는 것이다. 그러므로 이 보편적인 이상적인 고양이는 "실재(實在)"요  개개의 고양이들은 오직 "현상(現象)"에 지나지 않는다. 이것이 곧 실재와 현상 간의 구별이다. 이 때의 실재를 플라톤은 이데아라고 부른다.


  "많은 개체들이 공통된 명칭을  가질 때 그것들은 언제나  또 하나의 이데아, 즉 형상을 갖는다. 가령 침대는 무수히 많지만 침대의 이데아, 즉 그 형상은 오직 하나이다. 여러가지 개개의 침대는 실재가 아니며 오직 그 이데아의 모사(模寫)에 의해 만들어졌을 뿐이다."


... 생략 ...

=======================================


위에 아주 명확확하게 나와 있군요 ^_^


우리가 클래스라고 부르는 놈들은. "고양이에게 공통된 어떤 일반적인 성질을 갖고 있는 것"

객체라고 부르는 놈들은 개개의 고양이들은 오직 "현상(現象)"이 되는것입니다.


그 철학은 저기에 존재하는것이라고 볼 수도 있을까요?


글쎄요..전 철학을 몰라서 잘 모르겠습니다. ^_^

하지만. 왠지 클래스와 객체를 이해하는데 조금 더 도움이 될 것 같네요 ^_^



즐거운 하루 되세요~ ^_^


  1. 옷장수 2007.01.08 08:55 신고

    오~ 이제는 철학의 세계까지 ㅋㅋ Chan씨도 좋은 한주되세요.

+ Recent posts