라벨이 foundation of java인 게시물 표시

Comparator in Java

 이전 글에서는 Comparable에 대해서 정리해 보았습니다. 이번 글은 Comparator에 대해서 정리를 해볼 생각입니다. Comparable의 단점은 무엇 일까요?  굳이 단점을 들자면 만약 객체 비교 방법을 다르게 비교하고 싶다면 Comparable을 매번 수정해야하는 불편함이 생기겠죠. 그래서 있는 것이 Comparator라고 생각하시면 간단할 것 같아요. Comparator  일단 사용법을 먼저 보고 가죠. 1 2 3 4 5 6 7 8 Arrays.sort(object, new Comparator() { @ Override public int compare( Object o1, Object o2) { String s1 = o1.str; String s2 = o2.str; return s1.compareTo(s2); } });  sort의 2번째 파라미터로 comparator 객체를 생성하고 overriding을 해주면 원하는 형태로 객체를 비교할 수 있도록 해줍니다.

Comparable in Java

안녕하세요, 이번 Posting은 java의 comparable에 대해서 설명하도록 하겠습니다. Comparable       C omparable을 사용하시는 분들이 많을 것으로 생각되는데, 저 또한 알고리즘을 풀 때 자        사용하고 있습니다. 사용 법은 다음과 같습니다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Point implements Comparable<Point> { int x, y; Point( int x, int y) { this .x = x; this .y = y; } @ Override public int compareTo(Point o) { if (x > o.x) return 1 ; else if (x < o.x) return - 1 ; else { if (y > o.y) return 1 ; else if (y < o.y) return - 1 ; else return 0 ; } } }   Comparable class를 상속 받은 후 compareTo() 메소드를 overriding하여 객체를 비교할 수 있도록 해주는 역할을 하게 되죠. 예를 들어 Arrays.sort()를 사용할 때, 객체간의 비교를 위의 compareTo() 메소드를 사용하여 sorting을 하게 되죠.    저도 항상 헷갈리는 것이 있는데 compareTo() 메소드의 return 값입니다. 객체 자신과 파라미터로 넘어온 객체와 비교를 할 때, 만약 객체 자신이 크다면 양수를 ...

equals method and hashCode Method

이미지
 이번 Posting에서는 equals method와 hashCode method에 대해서 정리를 할 것이다. equals 1 2 3 public boolean equals (Object obj) { return ( this ==obj); } 메소드를 보면 파라미터로 넘어온 객체와 자기자신을 비교연산자를 통해 비교하여 값을 리턴하고 있다.  그렇다면 여기서 비교하고 있는 것은 "주소 값"일까? 아니면 주소 값이 가리키는 데이터일까? 정답은 주소 값을 비교하는 것이 맞다. 아래의 예제를 보면 확실할 것이다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Testing { public static void main (String[] args) { Value value1 = new Value( 1 ); Value value2 = new Value( 1 ); System. out . println ((value1. equals (value2)) ? "같다" : "다르다" ); > 다르다 value1 = value2; System. out . println ((value1. equals (value2)) ? "같다" : "다르다" ); > 같다 } } class Value { int x; Value( int x) { this . x = x; } } String Object 다음의 경우를 보자. 1 2 3 4 5 6 7 8 9 10 public class Testing { p...

JAVA HashMap 동작

이미지
HashMap은 키에 대한 해시 값을 사용하여 값을 저장하고 조회하며, 키-값 쌍의 개수에 따라 동적으로 크기가 증가하는 associate array라고 할 수 있다. 암호학이나 보안에 관심이 있는 사람이라면 Hash라는 것이 무엇인지 알고 있을 것이다. 예를 들어 어떤 문자열을 어떤 해시 함수를 통하면 일정한 길이의 해시된 값이 나오는데 이 값은 어떤 방법으로도 복원할 수 없다고 알려져 있다. 하지만 값에 따라 해시 값이 같은 즉 해시의 충돌이 발생할 수 있다. 해시 충돌이 없는 해시 함수를 완전 해시 함수라고 칭하지만 완전한 해시 함수를 구현하는 것은 사실상 불가능하다고 알려져 있다. 해시의 충돌을 막는 방법으로는 여러가지가 존재한다. 가장 일반적인 방법은 해시 함수의 표현 정수 범위 N보다 작은 M개의 원소가 있는 배열만을 사용하는 것이다. 즉, Index = hashCode(X) % M; 의 형태로 인덱스를 정할 수 있고 이 인덱스를 해시 버킷에 인덱스 값으로 사용한다. 하지만 이렇게 해도 1/M의 확률로 해시의 충돌이 발생하게 된다. 따라서 Separate Chaining 방식을 사용한다. 만약 버킷의 인덱스에 데이터가 들어있다면 해당 버킷에 linkedList를 생성하여 연결을 시키는 것이다. 이 방식은 현재 JAVA HashMap에서 사용하는 방식이다.

Garbage Collection

이번 Posting 에서는 GC에 대하여 정리를 할 것이다. 일반적으로 GC 실행될 때, stop-the-world라는 것을 실행한다. 이 것은 GC를 실행하는 스레드를 제외한 나머지 스레드는 모두 작업을 멈추는 작업이다. 이 것으로 인해 성능의 저하가 발생할 수 있기 때문에 GC 튜닝을 하는 것이다. Oracle HotSpot VM에서는 크게 2개의 물리적 공간을 나누었다. Young과 Old 영역이 그 공간이다. young 영역: 대부분의 새롭게 생성된 객체들이 위치하는 공간이다. 대부분의 객체가 금방 unreachable 상태가 되기 때문에 여기서 생성되었다가 사라진다. 이 영역에서 GC에 의해 사라지는 것은 Minor GC가 발생했다고 말한다. Old 영역: 계속해서 reachable 상태로 young 영역에서 살아남은 객체는 이 영역으로 복사된다. Old 영역이기 GC는 적게 발생한다. 여기서 발생하는 GC는 Major GC라고 말한다.  Old 영역에서 young 영역의 객체를 참조하고 있다면? card table이라는 것이 존재하여 card를 확인하여 GC 대상을 식별한다.

JVM이란? (2)

이미지
이번 Posting 에서는 Runtime data area에 대하여 정리를 한다. Runtime Data Areas는 JVM이 프로그램을 수행하기 위해 OS로 부터 별도로 할당 받은 메모리 공간이다. Runtime Data Areas는 다음과 같은 영역으로 나뉜다. PC Register                       - 별도의 thread Java Virtual Machine Stacks  - 별도의 thread Native Method Stacks         - 별도의 thread Method Area Heap Method Area, Heap는 모든 Thread가 메모리를 공유하기 때문에 동기화 이슈가 발생한다. PC register는 각 스레드마다 존재하고 스레드가 시작될 때 생성되고 또한 JVM 명령의 주소를 갖는다.  Stack은 JVM의 스택인데 역시 스레드 마다 존재하고 스레드가 시작될 때 생성된다. Stack frame 이라는 구조체를 저장하는 스택으로, 동작은 일반적인 Stack과 같다. Native method Stack은 JAVA 외의 언어로 작성된 네이티브 코드를 위한 스택으로 JNI(Java Native Interface)를 통해 호출하는 C/C++ 등의 코드를 수행하기 위한 스택임. 언어에 맞는 스택이 생성된다. 위 그림에는 class라고 되어있지만 메서드 영역은 모든 스레드가 공유하는 영역으로 JVM이 시작될 때 생성된다. 클래스, 인터페이스 의 정보, static 변수, 메서드의 바이트코드 등을 저장한다. Permanent Area라고도 불린다. 힙: 인스턴스 또는 객체를 저장하는 공간으로 가비지 컬렉션 대상이다. JVM 성능 등의 이슈에서 가장 많이 언급되는 공간이다. 힙 구성 방식이나 가비지 컬렉션 방법 등은 JVM 벤더의 재...

JVM이란? (1)

이미지
 이 Posting에서는 JVM의 구조 및 동작 원리에 대하여 이야기 해볼 것이다. JVM이 하는 일은 자바 바이트 코드를 해석하고 실행하는 것이다. 일반적인 프로그램과 JAVA 프로그램의 차이를 설명한 그림을 보고 시작하자. JVM은 JAVA와 OS 중간에서 중간자의 역할을 수행하는 녀석이다. 이 녀석은 JAVA가 편하게 동작할 수 있도록 재사용을 가능하게 해준다. 메모리를 Garbage collection을 통해 관리를 한다. 또 하나 일반적인 컴퓨터들은 레지스터 기반으로 동작하하지만 JVM은 스택기반의 가상 머신이다. 프로그램 실행 루틴 로딩 - OS는 어떤 실행 파일의 portable executable 파일의 header를 읽어 하드 디스크 같은 기억장치로 부터 RAM으로 적재한다. 패치 - 적재된 데이터는 여러 instruction으로 이루어져 있고 이 것을 순차적으로 CPU로 전달하여 읽어들이는 과정 디코딩 실행 - CPU에서 ALU로 전달 연산을 수행 JAVA 프로그램 실행 루틴 자 JAVA의 프로그램 실행 루틴을 알기 위해서 JVM의 구조를 좀더 명확하게 알 필요가 있다. JVM의 구조는 다음과 같다. loader를 통해 class file들을 JVM의 data area로 로딩을 한다. data area로 로딩되기 전에 class file들을 해석해야 하기 한다. 그 역할을 하는 것이 Execution engine 이 수행한다.

JAVA 변수란?

이미지
이번 Posting에서는 객체와 클래스에 대하여 정리를 할 것이다. 물론 "클래스는 무엇인가 ? 인스턴스는 무엇인가?"에 대한 기초적인 이야기를 할 것은 아니다. new new라는 키워드가 하는 일은 동적할당을 한다는 것은 모두가 알고 있을 것이다. 예를 들어 1 Test t = new Test(); 위와 같이 코드를 작성했다고 하면 Test 클래스의 인스턴스가 어떤 메모리 공간(method area)에 생성된다. 이렇게 생성된 공간을 가리키는 참조 변수는 t가 되는 것이다. 여기서 만약 다음과 같이 하면 어떻게 될까? 1 t = null ;  그대로 메모리 공간에 남게 되는 것일까? 아니면 자동으로 소멸이 되는 것일까? 정답은 남는다가 맞다. C에서는 계속 남아있게 되어 memory leak이 발생하지만, JAVA에서는 GC가 참조되지 않는 인스턴스의 메모리를 해제 시킨다. JAVA 메모리 할당 메모리를 이야기하기 위해서는 사전에 알아야할 것이 있다. 그 것은 바로 변수의 종류이다. java 변수에는 크게 3가지로 변수를 나눈다, "클래스 변수", "인스턴스 변수", "지역 변수" 이렇게 3가지가 존재하는데 다음 그림을 보면 이해가 빠를 것이다. 인스턴스 변수는 인스턴스가 생성될 때 만들어 진다. 또 다른 특징은 인스턴스 변수는 독립적인 저장공간을 가지므로 서로 다른 값을 가질 수 있다는 것이다. 클래스 변수는 클래스가 메모리에 올라갈 때 생성된다. 따라서 인스턴스를 생성하지 않은 때에도 사용이 가능하다. 그리고 앞에 public 키워드를 붙인다면 같은 프로그램 내에서 어디서나 접근할 수 있는 전역변수의 특성을 갖는다. 또한 인스턴스 변수 앞에 static 키워드만 붙이면 클래스 변수가 된다. 즉, 모든 인스턴스가 공유하는 변수가 된다는 이야기이다. 다음 코드를 보자 확실한 이해가 될 ...

Deep copy and shallow copy of array

이미지
 이번 Posting에서는 배열에 대해서 정리를 해보자.  배열의 기본적인 것은 제처 두고!! 배열의 복사에 대해서 얘기를 할 것이다. JAVA에는 깊은 복사와 얕은 복사 두 가지 방법의 복사가 있는데, 우선 얕은 복사부터 살펴보자. 얕은 복사는 함수를 통해서 return을 받거나 arr2 = arr1 이런식으로 대입을 통해서 참조 변수의 값만 전달하면 되는 것이다. 반면, 깊은 복사는 배열의 값을 직접 복사를 방법인데 for문을 통해 직접 값에 접근하여 복사를 행하거나 System.arraycopy() 함수를 통해서 깊은 복사를 행할 수 있다. 다음의 예제를 보면 확실히 알 수 있을 것이다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class CopyArray { public static void main(String[] args) { int [] origin = { 1 , 2 , 3 , 4 , 5 }; int [] deepCopiedArray = deepCopy(origin); int [] shallowCopiedArray = shallowCopy(origin); for ( int i = 0 ; i < origin.length; i++) { System.out. print (origin[i] + " " ); } System.out.println(); for ( int i = 0 ; i < deepCopiedArray.length; i++) { System.out. prin...

형 변환과 shift 연산

 이번 Posting에서는 형 변환과 shift 연산에 대하여 정리를 할 것이다. 형 변환은 평소에도 많이들 해봤을 것이고 또 많이 하고 있을 것이다.  하지만 java에서는 개발자의 편의를 위해 쉽게 할 수 있도록 구현해 놓았다.  자동 형 변환이 그 예이다. JVM단에서 형 변환을 통해서 손실이 없다고 판단되는 경우 알아서 형 변환을 해준다. byte -> short -> int -> long -> float -> double char와 short는 크기는 갖지만 범위가 다르기 때문에 형 변환을 할 때 손실이 발생할 경우가 있다. 서로간의 형 변환은 자동적으로 이루어지지 않는다.  연산에 대해서는 많이들 잘 알고 있기 때문에 shift 연산에 대해서만 정리를 하도록 하겠다. 알고리즘을 짜거나 어떤 코딩을 할 때 나누기 연산이나 곱셈을 많이 사용한다. 특히 2^n 형태의 곱셈이나 나눗셈을 하는 경우가 많은데 이 경우 연산의 비용을 낮추기 위해 사용되는 것이 shift 연산이다.  사실상 알고리즘을 짜다보면 직관적으로 곱하기나 나누기를 하는 경우가 많은데 shift 연산을 이용하면 좋을 것이라고 생각한다.

Type of variable

 JAVA에는 크게 Primitive type과 Reference Type의 변수가 있다는 것은 모두들 당연하게 알고 있을 것이다. 지금 부터는 P와 R이라고 간단하게 줄여서 부르도록 하겠다.  우선 P는 data를 실제 값으로 저장한다. 반면에 R은 data를 저장하는 것이 아니고 주소를 값으로 갖고 있다. 참고로 이 주소 값은 JVM에 의한 심볼릭 Reference이다. C언어에서는 R type의 변수 간의 연산이 가능 했었다. (ex. <<, operator 연산) 하지만 JAVA는 R type의 변수 간 연산이 불가능 하다 따라서 실제 연산에 사용되는 것은 모두 P type 변수가 하는 것이다. 또 하나 집고 넘어가야하는 것이 있다. 다음을 보자. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Example { byte b; short s; char c; int i; float f; double d; }; public class test { public static void main(String[] args){ Example ex = new Example(); } }  여기서 ex라는 R type 변수는 몇 바이트의 크기를 같는 변수인가? byte(1) + short(2) + char(2) + int(4) + float(4) + double(8) = 21 byte 인가? 답은 4 byte이다. 위에서 R type 변수는 주소를 갖는 변수라고 했다. 따라서 주소를 담는 크기 4 byte가 되는 것이다.