쓰레드의 문제점

변수 num에 저장되있는 값을 두개의 쓰레드가 증가시키는 상황일때

변수의값이 99일때 쓰레드 1이 변수 num의값 99를참조된 값을 증가된값 100을얻고 변수 num에저장한다.

이어서 쓰레드 2도 변수num의값 100을 참조하여 101을 얻고 연산이완료된 값을 num에 저장한다.

이는 매우 이상적인 상황이다 쓰레드 1이 변수 num에 저장된 값을 증가시키기 전에 쓰레드2로

cpu의 실행이 넘어갈수 있기 때문이다.

쓰레드1이 변수 num에 저장된 값99를 참조하여 증가연산 시킨 값 100을얻고 저장하기 전에

쓰레드 2가 num에 참조를 하게되면 증가하기 전 값인 99를 참조해 증가시킨값 100을 얻는다.

쓰레드1이 증가된값 100을 num에 저장하면 쓰레드 2도 증가된값 100을 저장한다.

증가된 변수에 쓰레드 2가 다시 100을 저장하는 일이 발생한다.

한쓰레드가 연산을 완료 할 때까지 다른 쓰레드가 접근하지 못하도록 하는것이 동기화(Synchronization)이다.


동기화메소드

1
2
3
public synchronized void increment(){
    
}
cs


메소드선언에 synchronized 선언을 해주면 이는 동기화 메소드가 된다.

동기화 메소드는 한 순간에 하나의 쓰레드만 호출이 가능하다.

쓰레드A가 이 메소드를 호출한 상태에서 쓰레드B가 이 메소드를 호출하면

쓰레드B는 쓰레드A가 메소드의 실행을 완료할 때 까지 기다리고 있다가 완료가 되면 실행을하게된다.

단점 - 실행시간이 오래걸린다. 쓰레드의 동기화로 인해 성능이 많이 저하된다.


동기화메소드에 의해서 동기화 되는 영역은 인스턴스 전체이다.

자바의 모든 인스턴스에는 하나의 열쇠가 존재한다. 이열쇠는 lock또는 monitor라한다.

synchronized 로 선언된 메소드에는 자물쇠가 걸리고 호출하려면 열쇠가 필요하다.

열쇠는 하나이기때문에 synchronized선언된 메소드는 동시에 둘 이상이 실행될수 없다.


동기화블록

동기화가 필요한 코드의양은 적은데 synchronized 선언이 돼있어 성능이 감소할때

동기화의 대상을 메소드 전부가 아니라 코드 블록 일부로 제한할 필요가 있다.

1
2
3
4
5
6
7
8
9
10
11
12
public synchronized int add(int n1, int n2){
    synchronized (this) {
        opCnt++;
    }
    return n1+n2;
}
public synchronized int min(int n1, int n2){
    synchronized (this) {
        opCnt++;
    }
    return n1-n2;
}
cs


동기화 블록에서 괄호 사이에 this가 삽입되어있다.

이 위치는 '어디에 있는 열쇠를 가져와 동기화를 하겠냐?' 를 묻는 위치이다.

동기화하지 말아야하는 상황의 메소드를 모두 동기화 메소드로선언하는것은 적절하지 못하다.

자바의 모든인스턴스에는 하나의 열쇠가 있다. 열쇠로 사용하기위해 생성된 인스턴스의 열쇠로

동기화 블럭에 열쇠를 지정하면 과도한 동기화로 인한 성능 저하가 발생하지 않는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class HaveTwoNum {
 
    Object key1 = new Object(); //열쇠 생성
 
    public void addOneNum1(){
        synchronized (this) {num1+=1;} //num1에 접근하는 메소드 this 키 기준으로 동기화
    }
    public void addTwoNum1(){
        synchronized (this) {num1+=2;} //num1에 접근하는 메소드 this 키 기준으로 동기화
    }
    public void addOneNum2(){
        synchronized (key) {num2+=1;}  //num2에 접근하는 메소드 key 키 기준으로 동기화
    }
    public void addTwoNum2(){
        synchronized (key) {num2+=2;} //num2에 접근하는 메소드 key 키 기준으로 동기화
    }
}
cs

this로부터 얻은 열쇠와 열쇠가 더필요할 때 Object인스턴스를 생성해 얻은 열쇠로 

동기화가 필요한 부분에 동기화를 한다.


'Java' 카테고리의 다른 글

쓰레드의 특성  (0) 2017.02.26
쓰레드 Thread  (0) 2017.02.26
Map<K,V> 인터페이스  (0) 2017.02.26
배열 (Array) / forEach  (0) 2017.02.26
HashSet<E> / TreeSet<E>  (0) 2017.02.26

쓰레드는 두개 이상 생성될 수 있다. 그렇기 때문에 자바 가상머신은(자바 가상머신안에 존재하는 스케줄러)

쓰레드의 실행을 스케줄링 해야 한다. 스케줄링에 사용되는 알고리즘은


우선순위가 높은 쓰레드의 실행을 우선한다.

동일한 우선순위의 쓰레드가 둘 이상 존재할 때는 CPU의 할당 시간을 분배해서 실행한다.

우선순위가 낮은 쓰레드 이더라도 높은 우선순위의 쓰레드가 CPU를 양보해서 실행의 기회를 얻게되면

최소 단위으 실행 시간은 보장을 받는다.


자바의 쓰레드에는 우선순위라는것이 할당된다. 이는 가상머신에 의해서 우선적으로 실행되어야 하는 쓰레드의 순위를 의미한다.

가장 높은 순위는 정수 10 가장낮은 순위는 정수 1로 표현한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class MessageSendingThread extends Thread{
    String message;
    public MessageSendingThread(String str){
        message = str;
    }
    public void run(){
        for(int i=0;i<100000;i++)
            System.out.println(message+"("+getPriority()+")");
    }
}
public class PriorityTest {
    public static void main(String[] args){
        MessageSendingThread tr1 = new MessageSendingThread("first");
        MessageSendingThread tr2 = new MessageSendingThread("second");
        MessageSendingThread tr3 = new MessageSendingThread("third");
        tr1.start();
        tr2.start();
        tr3.start();
    }
}
cs


getPriority() 메소드는 Thread 클래스의 인스턴스 메소드로 쓰레드의 우선순위를 반환한다.


1
2
3
4
5
6
public class MessageSendingThread extends Thread{
    String message;
    public MessageSendingThread(String str, int prio){
        message = str;
        setPriority(prio);
    }
cs


setPriority(int n) 메소드는 Thread 클래스의 인스턴스 메소드로 쓰레드의 우선순위를 변경한다.


1
2
3
4
5
Thread 클래스의 static 상수
Thread.MAX_PRIORITY 쓰레드의 최고 우선 순위 10
Thread.NORN_PRIORITY 중간순위 5
Thread.MIN_PRIORITY 최저순위 1
 
cs



쓰레드의 라이프 싸이클


쓰레드가 생성되면 네가지 상태중 한가지 상태에 있게 된다.


NEW 상태

쓰레드 클래스가 키워드 new 를 통해서 인스턴스화 된 상태를 가르킨다.

이 상태 에서는 자바 가상머신에 의해 관리가 되는 쓰레드의 상태는 아니다.

쓰레드라부르기에는 이른감이있는 상태이지만 자바에서는 이 상태부터 쓰레드라 표현한다.


Runnable 상태

쓰레드 인스턴스를 대상으로 start 메소드가 호출되면 해당 쓰레드는 Runnable 상태 가 된다. 

이는 모든 실행의 준비를 마치고스케줄러에 의해서 선택되어 실행되기를 기다리는 상태이다.

Runnable 상태에서 스케줄러에 의해서 실행의 대상으로 선택이 되어야 run 메소드가 호출이 된다.


Bloked 상태

실행중인 쓰레드가 sleep 또는 join 메소드를 호출하거나 CPU의 할당이 필요치 않는 입출력 연산을 하게되면

CPU를 다른 쓰레드에게 양보하고 본인은 Blocked 상태가 된다. Blocked 상태에서는 스케줄러의 선택을 

받을 수 없다, 다시 스케줄러의 선택을 받아서 실행이 되려면 Bloked 상태에 놓이게 된 원인이 제거되어서 

Runnable 상태로 돌아와야 한다.


Dead 상태

run메소드의 실행이 완료되어서 run 메소드를 빠져나오게 되면 해당 쓰레드는 Dead 상태가 된다.

그리고 이상태는 쓰레드의 실행을 위해서 할당 받았던 메모리를 비롯해서 각종 쓰레드 관련 정보가 완전히

사라지는 상태이다. 한번 Dead 상태가 된 쓰레드는 다시 Runnable 상태가 되지 못한다.

쓰레드의 실행을 위해 필요한 모든 것이 소멸되기 때문이다.



쓰레드의 메모리 구성 

쓰레드의 가장 큰 역할은 별도의 실행흐름 생성이다. 별도의 실행 흐름은 메소드의 호출을 통해 형성된다.

run메소드가 호출되고 run메소드 내에서 또 다른 메소드를 호출하면서 main메소드와는 다른 흐름을 형성한다.

이렇듯 main메소드와 다른 실행흐름을 형성하기 위해서는 별도의 스택이 쓰레드에게 할당 되어야 한다.

main쓰레드 이외에 두개의 쓰레드가 추가로 생성되면 가상머신은 다음의 형태로 메모리를 구성한다.


   공유-->

    메소드 영역

 <--공유

     스택 영역

     스택 영역

     스택 영역

   공유-->

      힙 영역

 <--공유


모든 쓰레드는 자신의 스택을 할당 받는다. 그러나 힙과 메소드 영역은 모든 쓰레드가 공유한다.

힙영역이 공유 된다는 것은 모든 쓰레드가 동일한 힙 영역에 접근이 가능함을 의미하는 것이고 이는

'A쓰레드가 만든 인스턴스의 참조값 만 알면 B쓰레드도 A쓰레드가 만든 인스턴스에 접근 가능하다.'는 뜻이다.




'Java' 카테고리의 다른 글

동기화 Synchronization  (0) 2017.02.26
쓰레드 Thread  (0) 2017.02.26
Map<K,V> 인터페이스  (0) 2017.02.26
배열 (Array) / forEach  (0) 2017.02.26
HashSet<E> / TreeSet<E>  (0) 2017.02.26

프로그램은 실행이 요청되면 메소드 영역 스택 영역 힙 영역 으로 메모리 공간이 할당되고

이 메모리를 기반으로 프로그램이 실행된다.

이렇듯 할당된 메모리 공간을 기반으로 실행 중에 있는 프로그램을 가리켜 '프로세스(process)'라 한다.

프로세스 내에서 프로그램의 흐름을 형성하는 주체를 쓰레드 라고 한다.

하나의 프로세스 내에 둘 이상의 쓰레드가 존재 할 수 있다.


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
public class ShowThread extends Thread{
    String threadName;
    
    public ShowThread(String name){
        threadName=name;
    }
    public void run(){
        for(int i=0; i<100;i++){
            System.out.println(threadName);
            try{
                sleep(100);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}
 
class ThreadUnderstand{
    public static void main(String[] args){
        ShowThread st1 = new ShowThread("first");
        ShowThread st2 = new ShowThread("second");
        st1.start();
        st2.start();
    }
}
cs


자바에서는 쓰레드도 인스턴스로 표현을 한다. 때문에 쓰레드의 표현을 위한 클래스가 정의되어야 하며,

이를 위해서는 thread 라는 이름의 클래스를 상속해야 한다.

쓰레드는 쓰레드만의 main 메서드를 지닌다. 단 이름이 main 아닌 run 이다.

sleep()는 Thread 클래스의 static 메소드로서 실행흐름을 일시적으로 멈추는 역할을 한다.

쓰레드의 프로그램의 흐름 형성은 start()메서드를 호출해야 한다.


Runnable 인터페이스

쓰레드 클래스의 정의를 위해서는 Thread 클래스를 상속해야만 한다. 

때문에 쓰레드 클래스가 상속 해야 할 또 다른 클래스가 존재한다면

인터페이스의 구현을 통한 방법으로 쓰레드를 생성한다.


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
public class Sum {
    int num;
    public Sum(){num=0;}
    public void addNum(int n){num+=n;}
    public int getNum() {return num;}
}
 
class AdderThread extends Sum implements Runnable{
    int start, end;
    
    public AdderThread(int s,int e){
        start=s;
        end=e;
    }
    public void run(){
        for(int i =start; i<=end;i++)
            addNum(i);
    }
}
 
public class RuunnableThread {
    public static void main(String[] args){
        AdderThread at1 = new AdderThread(150);
        AdderThread at2 = new AdderThread(51,100);
        Thread tr1 = new Thread(at1);
        Thread tr2 = new Thread(at2);
        tr1.start();
        tr2.start();
        
        try{
            tr1.join();
            tr2.join();
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("1~100까지의 합"+(at1.getNum()+at2.getNum()));
    }
}
cs


Runnable 인터페이스는 run 메소드 하나로 이루어져 있다.

Runnable 인터페이스를 구현하는 클래스를 대상으로 start 메소드를 호출할수 없다.

start 메소드는 Thread 클래스의 메소드이기 때문이다.

Thread 클래스에는 Runnable 인터페이스를 구현하는 인스턴스의 참조값을 전달받을 수 있는  생성자가 정의되어 있다.

join() 메소드는 해당 쓰레드가 종료 될 때 까지 실행을 멈출 때 호출하는 메소드이다.

join()메소드가 호출 된 모든 쓰레드가 종료되어야 다음 코드를 실행한다.

'Java' 카테고리의 다른 글

동기화 Synchronization  (0) 2017.02.26
쓰레드의 특성  (0) 2017.02.26
Map<K,V> 인터페이스  (0) 2017.02.26
배열 (Array) / forEach  (0) 2017.02.26
HashSet<E> / TreeSet<E>  (0) 2017.02.26

Map<K,V> 인터페이스를 구현하는 컬렉션 클래스들의 데이터 저장방식을 가르켜

Key-value 방식이라 한다.

Key는 데이터를 찾는 열쇠(이름)을 의미한다. value는 찾고자하는 실질적인 데이터를 의미한다.

Collection<E> 인터페이스를 구현하는 클래스들이 value만 저장하는 구조였다면

Map<K,V>는 value를 저장할때 이를 찾는데 사용하는 Key를 함께 저장하는 구조이다.

Map<K,V>를 구현하는 대표적인 클래스로 HashMap<K,V>와 TreeMap<K,V>가 있다.


HashMap<K,V>

HashSet<E> 클래스가 해시 알고리즘 기반으로 구현되어 있듯이, HashMap<K,V>클래스도 

해시 알고리즘 기반으로 구현되어 있다. 해시 알고리즘의 장점인 빠른 검색속도 역시 반영된다.

value 에 상관없이 중복된 key의 저장은 불가능하다.

value 는 같더라도 key가 다르면 둘 이상의 데이터 저장도 가능하다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class HashMapTest {
    public static void main(String[] args){
        HashMap<Integer,String> hMap = new HashMap<Integer,String>();
        //저장
        hMap.put(1"one");
        hMap.put(2"two");
        hMap.put(3"three");
        hMap.put(4"four");
        hMap.put(5"five");
        //호출
        System.out.println(hMap.get(1));
        System.out.println(hMap.get(5));
        //제거
        hMap.remove(3);
    }
}
cs



TreeMap<K,V>

TreeMap<K,V> 클래스는 트리 자료구조를 기반으로 구현이 되어있어 정렬된 상태로 저장된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class TreeMapTest {
    public static void main(String[] args){
        TreeMap<Integer,String> tMap = new TreeMap<Integer,String>();
        
        tMap.put(1"one");
        tMap.put(2"two");
        tMap.put(3"three");
        tMap.put(4"four");
        tMap.put(5"five");
 
        NavigableSet<Integer> navi = tMap.navigableKeySet();
        
        //오름차순 출력
        Iterator<Integer> itr = navi.iterator();
        while(itr.hasNext())
            System.out.println(tMap.get(itr.next()));
 
        //내림차순 출력
        itr = navi.descendingIterator();
        while(itr.hasNext())
            System.out.println(tMap.get(itr.next()));
    }
}
cs


Key를 기준으로 정렬되어 저장이 된다.


navigableKeySet 메서드가 호출되면 인터페이스 NavigableSet<E>를 구현하는 인스턴스가 반환된다.

이때 E는 Key 의 자료형인 Integer 가 되며 반환된 인스턴스에는 저장된 데이터들의 Key의 정보가 저장되어 있다.


NavigableSet<E> 인터페이스는 Set<E> 인터페이스를 상속한다 

즉 반복자를 얻기 위해서 iterator 메소드 호출이 가능하다. 호출해서 얻은 반복자로 저장된 Key에 접근이가능하다.

내림차순으로의 접근에 사용되는 반복자를 얻기 위해서 decendingIterator 메소드의 호출도 가능하다.



 

'Java' 카테고리의 다른 글

쓰레드의 특성  (0) 2017.02.26
쓰레드 Thread  (0) 2017.02.26
배열 (Array) / forEach  (0) 2017.02.26
HashSet<E> / TreeSet<E>  (0) 2017.02.26
Set<E>  (0) 2017.02.26

배열은 여러개의 연관된 데이터를 저장하는데 사용되는 데이터 타입이다.

배열은 int형 같은 기본자료형 만으로 선언해야 하는것이 아니다. 클래스 기반으로도 선언이 가능하다.


1차원 배열


배열의 생성

1
2
int[] arr;
arr = new int[7];
cs

길이가 7인 인트형의 배열이다.

[]안에 배열의 길이를 지정한다.


배열의 접근

1
2
3
int[] arr = new int[7];
arr[0= 1;
arr[1= 2;
cs


선언과 동시에 초기화

1
2
3
int[] arr = new int[3] {1,2,3}; //방법1
int[] arr = new int[] {1,2,3}; //방법2
int[] arr = {1,2,3}; //방법3
cs


최대값,최소값

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
public class ArrayTest {
    public static void main(String[] args){
        int[] arr = new int[3];
        arr[0]=50;
        arr[1]=20;
        arr[2]=30;
        
        int max=arr[0];
        int min=arr[0];
        
        //최대값 저장
        for(int i=0;i<arr.length;i++){ 
            if(arr[i]>max){
                max=arr[i];
            }
        }
        //최소값 저장
        for(int i=0;i<arr.length;i++){
            if(min>arr[i]){
                min=arr[i];
            }
        }
        System.out.println(min);
        System.out.println(max);
    }
}
cs

 

 

2차원 배열


1
2
3
4
5
6
7
8
int[][] arr = new int[3][4]; //2차원 배열 생성
 
int[][] arr ={
    {1,2,3,4//1행 초기화
    {5,6,7,8//2행 초기화
    {9,10,11,12//3행 초기화
}
 
cs
 
1
2
3
4
5
System.out.println(arr.length); //배열의 세로길이
 
for(int i=0; i<arr.length; i++)
    System.out.printf("%d 행의길이 : %d \n",i+1,arr[i].length);
    //배열의 가로길이
cs


배열의 가로길이가 일정하지 않은 배열은 'Regged Array' 라고 한다.

 

for-each


1
2
3
4
5
6
7
8
9
10
11
12
public class ArrayTest {
    public static void main(String[] args){
        int[] arr = {123};
        
        //배열의 값 모두 출력
        for(int i =0; i<arr.length;i++)
            System.out.println(arr[i]);
        
        for(int e : arr)
            System.out.println(e+"");
    }    
}
cs


for(int e : arr) 

배열 요소를 지칭하는 변수 e 배열의 이름 arr


'Java' 카테고리의 다른 글

쓰레드 Thread  (0) 2017.02.26
Map<K,V> 인터페이스  (0) 2017.02.26
HashSet<E> / TreeSet<E>  (0) 2017.02.26
Set<E>  (0) 2017.02.26
Iterator 반복자  (0) 2017.02.26

HashSet<E>

해시알고리즘

HashSEt<E> 클래스를 제대로 활용하기 위해서는 간단하게나마 해시 알고리즘을 이해해야 한다.

num%3

3, 5, 7, 12, 25, 31 이라는 집합이 있을때 집합 원소들을 3으로 나누면 연산의 결과를 0,1,2, 3가지로 나눌수 있다.

연산결과 0 : 3, 12

연산결과 1 : 5

연산결과 2 : 7, 25, 31

이렇게 부류가 나뉜 상태에서 집합에 정수가 5가 존재하는지 확인하는 가장 효율적인 방법은

찾고자 하는 수인 5를 3으로 나머지 연산하여 나온 결과가 속하는 부류를 찾는것이 가장 효율적인 방법이다.

그럼 나머지 연산의 결과가 0과 1 인 부류는 검색의 대상에서 제외가 된다. 즉 검색의 대상이 줄어들은것이다.

이것이 해시 알고리즘의 장점이다. 해시 연산의 결과값 0, 1 ,2 를 가르켜 '해시 값' 이라 하며 

이 해시 값을 기준으로 데이터를 구분하게 된다.

검색1단계 -> 구하고자 하는 정수의 해시값을 계산한다.

검색2단계-> 해시 값이 속하는 부류 내에서 구하고자 하는 정수가 존재하는지 확인한다.

이렇게 두단계를 거치는 이유는 검색의 효율성과 속도 향상을 위한 것이다.


HashSet<E> 클래스는 해시 알고리즘을 적용하여 데이터를 저장하고 검색한다.

HashSet<E> 클래스의 장점은 "매우 빠른 검색속도" 이다.

HashSet<E> 클래스는 데이터 저장시에 검색의 과정을 거친다. 중복을 허용하지 않기 때문이다.

중복된 데이터가 있는지 판단은 

Object 클래스의 hashCode 메소드의 반환값을 해시 값으로 활용

Object 클래스의 equals 메소드의 반환값을 이용해서 내용 비교

Object 클래스의 hashCode 메소드는 인스턴스가 다르면 구성 내용에 상관없이 전혀 다른 해시값을 반환하게 되어있다.

따라서 구성이나 값은 같지만 해시코드가 다른 데이터를 저장하게 된다.

값은 같지만 다른 인스턴스를 동일한 데이터로 인식이 되게 하려면

public int hashCode() 메소드와 public boolean equals(Object obj) 메소드를 오버라이딩 해야된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class HashTest {
 
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        HashSet<String> hs = new HashSet<String>();
        hs.add(new String("first"));
        hs.add(new String("second"));
        hs.add(new String("third"));
        hs.add(new String("first"));
        
        System.out.println("저장된데이터수 :"+hs.size());
        Iterator<String> itr = hs.iterator();
        while(itr.hasNext())
            System.out.println(itr.next());
    }
 
}
cs




TreeSet<E>


TreeSet<E> 클래스는 '트리(Tree)' 라는 자료구조를 기반으로 구현되어 있다.

트리는 데이터를 정렬된 상태로 저장하는 자료구조이다. 

따라서 이를 기반으로 구현된 TreeSet<E>클래스 역시 데이터를 정렬된 상태로 유지한다.

TreeSet<E> 클래스는 중복된 데이터의저장을 허용하지 않고 오름차순으로 정렬이 이뤄진다.

TreeSet<E> 클래스에는 decendingIterator 라는 내림차순으로 검색해 반환하는 메소드로 

내림차순으로정렬해 출력도가능하다.


1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args){
        TreeSet<Integer> ts =new TreeSet<Integer>();
        ts.add(1);
        ts.add(4);
        ts.add(3);
        ts.add(4);
        ts.add(2);
        
        Iterator<Integer> itr = ts.iterator();
        while(itr.hasNext()){
            System.out.println(itr.next());
        }
cs


데이터의 중복저장미허용과 오름차순정렬에의한 결과 1 2 3 4 


정렬의 방식이 숫자라면 정렬의 기준이 오름차순이 가능하지만

정렬의대상이 인스턴스라면 정렬 기준을 Comparable<T> 인터페이스를 구현해 정의한다.

Comparable<T>인터페이스는 다음과 같이 정의한다.


인자로 전달된 obj의 멤버변수가 작다면 양의정수 반환

인자로 전달된 obj의 멤버변수가 크다면 음의정수 반환

인자로 전달된 obj의 멤버변수가 같다면 0반환

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Person implements Comparable<Person> {
    String name;
    int age;
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    @Override
    public int compareTo(Person o) {
        if(age>o.age)
            return 1//매개변수가 작다면 양수 반환
        else if(age<o.age)
            return -1//매개변수가 크다면 음수 반환
        else
            return 0//같다면 0 반환
        
        return 0;
    }
}
cs

compareTo 메서드를 통해 인스턴스간의 크고 작음을 비교 가능하게 되었다.

TreeSet<T> 는 Person 인스턴스가 저장될 때 마다 compareTo메서드를 호출해 

반환되는 값을 기준으로 정렬을 진행 할 것이다.


comparator<T> 

comparator<T> 인터페이스는 문자열의 정렬 기준을 정의할수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
public class strLenComparator implements Comparator<String> {
 
    @Override
    public int compare(String o1, String o2) {
        if(o1.length()>o2.length())
            return 1;
        else if(o1.length()<o2.length())
            return 2;
        else
            return 0;
    }
}
cs


 

'Java' 카테고리의 다른 글

Map<K,V> 인터페이스  (0) 2017.02.26
배열 (Array) / forEach  (0) 2017.02.26
Set<E>  (0) 2017.02.26
Iterator 반복자  (0) 2017.02.26
List<E> / ArrayList<E> / LinkedList<E>  (0) 2017.02.26

Set<E> 인터페이스의 특성

Set<E> 인터페이스를 구현하는 클래스들은 데이터의 저장순서를 유지하지않는다.

Set<E> 인터페이스를 구현하는 클래스들은 데이터의 중복 저장을 허용하지 않는다.


Set 는 집합 이라는 뜻이다. 

Set연산 은 교집합(intersect), 차집합(difference), 합집합(union)과 같은 연산을 할 수 있다.


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
    public static void main(String[] args) {
        HashSet<Integer> A = new HashSet<Integer>();
        A.add(1);
        A.add(2);
        A.add(3);
         
        HashSet<Integer> B = new HashSet<Integer>();
        B.add(3);
        B.add(4);
        B.add(5);
         
        HashSet<Integer> C = new HashSet<Integer>();
        C.add(1);
        C.add(2);
         
        System.out.println(A.containsAll(B)); // false
        System.out.println(A.containsAll(C)); // true
         
        //A.addAll(B);
        //A.retainAll(B);
        //A.removeAll(B);
         
        Iterator hi = A.iterator();
        while(hi.hasNext()){
            System.out.println(hi.next());
        }
    }
 
}
cs

 

1
2
3
4
부분집합 (subset)
 
System.out.println(A.containsAll(B)); // false
System.out.println(A.containsAll(C)); // true
cs

 

1
2
3
합집합(union)
 
A.addAll(B);
cs


1
2
3
교집합(intersect)
 
A.retainAll(B)
cs

 


1
2
3
차집합(difference)
 
A.removeAll(B);
cs

  https://opentutorials.org/course/1223/6446





'Java' 카테고리의 다른 글

배열 (Array) / forEach  (0) 2017.02.26
HashSet<E> / TreeSet<E>  (0) 2017.02.26
Iterator 반복자  (0) 2017.02.26
List<E> / ArrayList<E> / LinkedList<E>  (0) 2017.02.26
이스케이프 시퀀스(Escape Sequence)  (0) 2017.02.26

컬렉션 인터페이스를 구현하고 있는 모든 클래스들은 iterator 메소드를 통해서 반복자를 제공한다.


Collection<E> 인터페이스에는 iterator 라는 메소드가 정의되어 있다.

Iterator<E> iterator()

iterator 메소드가 호출되면 인스턴스가 생성된다. 이 인스턴스는 Iterator<E> 인터페이스를 구현하는 클래스이다.

iterator 메소드는 이인스턴스의 참조값을 리턴한다.


Iterator 는 반복자 라는 뜻이다. 컨테이너에 담겨져 있는 값들을 하나씩

꺼내서 처리를 할수 있도록 하는것이 Iterator의 역할이다.


Iterator는 3가지 메소드를 가지고 있다.

boolean hasNext() 참조할 다음번 요소가 존재하면 true 반환

E next() 다음번 요소를 반환

void remove() 현 위치의 요소를 삭제


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
import java.util.Iterator;
import java.util.LinkedList;
 
class InteratorUsage{
    public static void main(String[] args){
        LinkedList<String> list = new LinkedList<String>();
        list.add("First");
        list.add("Second");
        list.add("Third");
        list.add("Fourth");
        
        Iterator<String> itr = list.iterator();
        
        System.out.println("반복자를 이용한 1차출력과 \"Third\"삭제");
        while(itr.hasNext())
        {
            String curStr = itr.next();
            System.out.println(curStr);
            if(curStr.compareTo("third")==0)
                itr.remove();
        }
        
        System.out.println("\n\"Third\"삭제 후 반복자를 이용한 2차 출력 ");
        itr= list.iterator();
        while(itr.hasNext())
            System.out.println(itr.next());
    }
}
cs


 

1
2
for(String str : list)
    System.out.println(str);
cs

for-each 문을 사용하면 반복자를 생성하지 않아도 되기 때문에 코드를 보다 간결하면서도 명확하게 구성할수 있다.

그러나 예제의 첫번째 while 문은 대체가 불가능 하기 때문에(데이터의 삭제) 두가지 방식 모두에 익숙해질 필요가 있다.



'Java' 카테고리의 다른 글

HashSet<E> / TreeSet<E>  (0) 2017.02.26
Set<E>  (0) 2017.02.26
List<E> / ArrayList<E> / LinkedList<E>  (0) 2017.02.26
이스케이프 시퀀스(Escape Sequence)  (0) 2017.02.26
제네릭(Generics)  (0) 2017.02.25

+ Recent posts