'java'에 해당되는 글 3건

  1. 2015.02.27 순서가 보장되는 HashMap - LinkedHashMap
  2. 2015.02.16 Java this 키워드 1
  3. 2015.02.14 Java final 키워드

데이터를 모아서 저장하고 관리하는데 있어서 많은 자료형들이 유용하게 사용됩니다.

ArrayList, Map, Vector, Stack, Queue 등등!

 

각기 다른 장점과 단점을 가지고 있지만

요새 특히 많이 사용하고 있는 것은 HashMap 입니다.

 

key 와 value 의 1:1 한쌍으로 데이터를 저장 / 관리할 수 있고

key 를 통해 저장된 value 를 손쉽게 얻어 올 수 있는 매우 유용한 자료형입니다.

(key 의 중복은 허용되지 않습니다.)

 

key 기반의 데이터 저장 구조이기 때문에 자연스럽게 저장 순서는 의미를 갖지 않게 되어서

저장된 데이터를 출력해 보면 추가했던 순서와는 전혀 다른 형태의 모습으로 여기저기 흩어져 있는 것을 확인 할 수 있습니다.

 

그런데 아주 가끔 입력한 순서대로 저장이 필요한 순간이 있습니다.

마치 ArrayList 처럼 순서대로 데이터를 입력하고 싶은 것이죠.

그럴 때 사용하는 자료형이 바로 LinkedHashMap 입니다.

 

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
42
43
44
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
 
public class HashMapTest {
    public static void initData(Map<StringString> map) {
        map.put("key1""1");
        map.put("key2""2");
        map.put("key3""3");
        map.put("key4""4");
        map.put("key5""5");
        map.put("key6""6");
        map.put("key7""7");
        map.put("key8""8");
        map.put("key9""9");
        map.put("key10""10");
    }
    
    public static void printResult(Map<StringString> map) {
        Set<String> set = map.keySet();
        Iterator<String> iter = set.iterator();
        while (iter.hasNext()) {
            String key = ((String)iter.next());
            String value = map.get(key);
            System.out.println("key : " + key + ", value : " + value);
        }
    }
 
    public static void main(String[] args) {
        // HashMap
        System.out.println("====== HashMap Test ======");
        Map<StringString> hashMap = new HashMap<StringString>();
        initData(hashMap);
        printResult(hashMap);
        
        // LinkedHashMap
        System.out.println("====== LinkedHashMap Test ======");
        Map<String,String> linkedHashMap=new LinkedHashMap<StringString>();
        initData(linkedHashMap);
        printResult(linkedHashMap);
    }
}
cs

 

<출력>

====== HashMap Test ======
key : key4, value : 4
key : key3, value : 3
key : key6, value : 6
key : key5, value : 5
key : key2, value : 2
key : key1, value : 1
key : key10, value : 10
key : key8, value : 8
key : key7, value : 7
key : key9, value : 9
====== LinkedHashMap Test ======
key : key1, value : 1
key : key2, value : 2
key : key3, value : 3
key : key4, value : 4
key : key5, value : 5
key : key6, value : 6
key : key7, value : 7
key : key8, value : 8
key : key9, value : 9
key : key10, value : 10

 

출력 결과에서 처럼 HashMap 은 입력된 순서와 전혀 상관 없이 데이터가 흩어져 있는 반면에

LinkedHashMap 은 입력된 순서대로 차곡차곡 데이터가 쌓여 있는 것을 확인 할 수 있습니다.

 

언뜻 보기에는 ArrayList 를 사용하는 것과 차이가 없어 보일 수 있지만

LinkedHashMap 의 경우는 HashMap 의 장점을 그대로 가지고 있기 때문에

동일한 key 의 중복을 막아주고, 특정 key 의 value 를 찾고자 할 때 for 문을 돌며 전체 값을 검색할 필요가 없습니다.

 

또한 순서대로 입력되어 있기 때문에 전체의 값을 순서대로 operation 해야 할 때도 매우 유용합니다.

 

 


 

마지막으로 LinkedHashMap 에는 특별한 기능을 가진 removeEldestEntry() 메소드가 존재합니다.

 

protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {

return false; 

}

 

이 메소드는 put() 메소드가 호출될 때 불리게 되는데 마지막으로 입력된 순서를 기억하고

LinkedHashMap 에 입력된지 가장 오래된 데이터를 파라미터로(eldest) 전달받게 됩니다.

 

1
2
3
4
5
6
7
8
9
System.out.println("====== LinkedHashMap2 Test ======");
Map<StringString> linkedHashMap2=new LinkedHashMap<StringString>() {
    @Override
    protected boolean removeEldestEntry(Entry<StringString> arg0) {
        return size() == 6true : false;
    }
};
initData(linkedHashMap2);
printResult(linkedHashMap2);
cs

 

따라서 removeEldestEntry() 메소드를 오버라이드(override) 해서 다음과 같이 사용하면

6번째 데이터가 입력될 때, 입력된지 가장 오래된 데이터(1번째 데이터)가 삭제되고

linkedHashMap2 의 최대 입력 갯수는 5 가 되게 됩니다. (지정된 크기의 데이터만 입력 가능합니다.)

 

<출력>

====== LinkedHashMap2 Test ======
key : key6, value : 6
key : key7, value : 7
key : key8, value : 8
key : key9, value : 9
key : key10, value : 10

 

Posted by maze1008
,

Java this 키워드

IT/Java 2015. 2. 16. 08:30

자바에서(Java) this 는 '객체, 자기 자신' 을 나타냅니다.

 

주로 3가지 형태로 사용되고 있으며 예를 들어 하나씩 살펴보도록 하겠습니다.

 

 

1. 클래스의 속성과 생성자/메소드의 매개변수(input parameter)의 이름이 같은 경우

- 클래스 속성을 사용할 때 this 키워드를 붙여줍니다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Fruit {
    public String name;
    public String color;
    public double weight;
    public int count;
        
    public Fruit(String name, String color, double weight, int count) {
        name = name;
        color = color;
        weight = weight;
        count = count;
    }
    
    public static void main(String[] args) {
        Fruit banana = new Fruit("banana""yellow"5.010);
        System.out.println("name : " + banana.name);        // name : null
        System.out.println("color : " + banana.color);      // color : null
        System.out.println("weight : " + banana.weight);    // weight : 0.0
        System.out.println("count : " + banana.count);      // count : 0
    }
}
cs

 

일반적으로 생성자 또는 set / get 메소드의 매개변수(input parameter) 이름은

클래스의 속성 이름과 동일하게 정의되어 사용됩니다.

 

위에서 보여지는 생성자의 매개변수 역시 클래스 속성과 동일한 이름으로 정의되어 있습니다.

그런데 main 메소드에서 Fruit 객체를 생성하고 속성 값들을 출력해 보니 예상치 못한 결과가 나타납니다.

초기화가 이루어지지 않았습니다!! ("banana", "yellow", 5.0, 10 이라고 값을 입력했는데 말이죠!)

 

생성자의 구현부분에서 name = name; 처럼 사용하게 되면

"name 매개변수 = name 매개변수" 형태가 되어 Fruit 객체의 name 속성에는 값이 입력되지 않습니다.

 

안타깝게도 java 는 좌측의 name 이 Fruit 객체의 name 속성을 가리키고 있다는 사실을 인지하지 못합니다.

이럴 때 바로 this 키워드가 사용됩니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Fruit {
    public String name;
    public String color;
    public double weight;
    public int count;
        
    public Fruit(String name, String color, double weight, int count) {
        this.name = name;
        this.color = color;
        this.weight = weight;
        this.count = count;
    }
    
    public static void main(String[] args) {
        Fruit banana = new Fruit("banana""yellow"5.010);
        System.out.println("name : " + banana.name);        // name : banana
        System.out.println("color : " + banana.color);      // color : yellow
        System.out.println("weight : " + banana.weight);    // weight : 5.0
        System.out.println("count : " + banana.count);      // count : 10
    }
}
cs

 

 this.name = name; 은

"Fruit 객체의 name 속성 = name 매개변수" 형태가 되어 Fruit 객체의 속성에 값을 입력하게 됩니다.

 

여기에서의 this 키워드는 객체 자신의 속성을 나타내게 되는 것 입니다.

 

 

2. 클래스에 오버로딩된 다른 생성자 호출 

- 생성자의 최상단(가장 먼저)에 사용되어야 합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Fruit {
    public String name;
    public String color;
    public double weight;
    public int count;
        
    public Fruit(String name, String color) {
        // Fruit(String name, String color, double weight, int count) 를 호출
        this(name, color, 0.00);
    }
    
    public Fruit(String name, String color, double weight, int count) {
        this.name = name;
        this.color = color;
        this.weight = weight;
        this.count = count;
    }
}
cs

 

하나의 클래스에 여러개의 생성자가 오버로딩 되어 있을 때

일부분을 제외하고는 서로 중복된 코드를 가지고 있는 경우가 많이 있습니다.

 

이런 순간에 내부에 정의된 다른 생성자를 호출하여 코드의 중복을 피하고 깔끔한 소스를 작성할 수 있습니다.

같은 클래스에 오버로딩된 다른 생성자를 호출때에도 this 키워드가 사용됩니다.

 

생성자를 호출할 때에는 원하는 생성자의 매개변수를 확인한 후 

메소드를 호출하는 것 처럼 this(매개변수...) 의 형태로 이용하면 됩니다.

 

위에서는 2개의 매개변수를 입력받은 생성자(name, color)의 구현부분에서

4개의 매개변수를 입력받는 생성자(name, color, weight, count) 를 호출하고 있습니다.

 

 

3. 객체 자신의 참조값을 전달하고 싶을 때 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Fruit {
    public String name;
    public String color;
    public double weight;
    public int count;
            
    public Fruit(String name, String color, double weight, int count) {
        this.name = name;
        this.color = color;
        this.weight = weight;
        this.count = count;
    }
 
    public Fruit getFruitInstance() {
        return this;
    }
}
cs

 

어떤 메소드에서는 동작을 완료하고 리턴값으로

어떤 메소드에서는 내부에서 호출하고자 하는 메소드의 매개변수(input parameter) 로 

객체, 자기 자신의 참조값을 전달하고 싶은 경우가 있습니다.

 

이럴때에는 getFruitInstance() 메소드의 구현부분에서처럼 this 키워드를 이용함으로써 구현이 가능합니다.

 

 

자바에서 this 는 자주 사용되는 키워드입니다.

3가지 상황에서처럼 명시적으로 this 를 사용하지 않더라고 "객체, 자기 자신" 을 나타내야 할 때는 묵시적으로

앞부분에 this 가 기입되어 있다고 생각하시면 이해하시기에 더욱 도움이 될 것 같습니다.

 

 

Posted by maze1008
,

Java final 키워드

IT/Java 2015. 2. 14. 16:09

자바에서(Java) final 은 상수를 표현하기 위한 예약어 입니다.

 

마지막이라는 단어의 뜻 처럼 선언한 그대로 사용하라는 의미입니다.

변수, 메소드, 클래스에서 모두 이용되고 있는데요.

 

지금부터 각각의 의미에 대해서 살펴보도록 하겠습니다.

 

 

1. final 변수

- 상수라고도 불립니다.

- 변수를 선언과 동시에 초기화하며 이후에 값을 수정할 수 없습니다.

- 오직 get 만 가능합니다.

 

1
2
3
4
5
6
7
8
9
public class Fruit {
    public static void main(String[] args) {
        // 선언 및 초기화
        final int count = 10;
        
        // 수정
        count = 15;
    }
}
cs

 

count 변수를 선언할 때 final 키워드를 추가해 줌으로써 상수임을 나타내고 있습니다.

그리고 선언과 동시에 초기화를 진행하여 10 을 대입해 주었습니다.

 

이후에 값을 15로 수정하려고 하면 다음과 같은 에러가 발생합니다.

count 변수에 값을 넣을 수 없다는 뜻 입니다.

 

 

일반적으로 final 변수는 프로그램 전체에 걸쳐 사용되는 경우가 많아서

위에서 처럼 특정 메소드 내부에서 선언하기 보다는 클래스에 static 키워드와 함께 정의되어 사용됩니다.

 

1
2
3
4
5
6
7
8
9
10
11
public class Fruit {
    
    // 선언 및 초기화
    static final int COUNT = 10;
    static final double PI = 3.14;
    static final String FILE_NAME = "Config";
    
    public static void main(String[] args) {
        // TODO
    }
}
cs

 

모든 변수 타입(int, double, String 등)에 적용할 수 있으며

폴더 / 파일 이름, DB 컬럼명, 사이즈 등의 정보를 표현하는데 유용합니다.

 

(소스 상에서 필요할 때마다 "Config" 라는 값을 입력 해야한다면 오타가 발생할 확률이 높고, 개발중에 "Setting" 이라는 이름으로 변경해야 할 상황이 발생한다면 일일이 수정해야 하는 불편함이 생겨날 것입니다. 이러한 상황에 static final 변수로 선언하여 사용하고 있다면 안전성과 편리함을 동시에 높여줄 수 있겠죠!)

 

 

2. final 메소드

- 오버라이딩(Overriding) 이 불가능합니다.

- 상속 받은 그대로 사용해야 합니다.

 

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
public class Fruit {
    public String name;
    
    public void setName(String name) {
        this.name = name;
    }
    
    public final String getName() {
        return name;
    }
}
 
public class Banana extends Fruit {
 
    @Override
    public void setName(String name) {
        this.name = "Fruit Name : " + name;
    }
 
    public String getName() {
        return name;
    }
    
    public static void main(String[] args) {
        // TODO
    }
}
 
cs

 

Fruit 클래스에는 name 에 대한 set / get 메소드가 존재합니다.

여기서 집중하셔야 할 부분은 getName() 메소드 앞에 위치한 final 키워드 입니다.

 

Banana 클래스는 Fruit 클래스를 상속받아

setName() 메소드를 원하는 형태로 오버라이딩 했습니다.

 

그런데 final 메소드인 getName() 도 오버라이딩이 가능할까요?

이 때 다음과 같은 에러가 발생합니다. 즉, 오버라이딩이 불가능 하다는 뜻입니다.

 

 

 

3. final 클래스

- 상속(Inheritance) 이 불가능합니다.

- subclass 를 만들수 없습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public final class Fruit {
    public String name;
    
    public void setName(String name) {
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
}
 
public class Banana extends Fruit {
 
    public static void main(String[] args) {
        // TODO
    }
}
cs

 

이번에는 Fruit 클래스 앞에 final 키워드가 위치해 있습니다.

 

앞에서와 같이 Banana 클래스에서 Fruit 클래스를 상속하려고 하는데요.

 

 

예상하셨다시피 Fruit 클래스는 final 클래스이기 때문에 상속이 불가능하다는 에러가 나타납니다.

 

 

 

final 메소드와 클래스는 주로 라이브러리 형태의 프로젝트를 작성할 때 사용됩니다.

(라이브러리를 완전히 이해하지 못한 상태에서 재정의 한다면 에러가 발생할 확율이 높아지기 때문에 원천적으로 수정이 불가능하도록 막아놓는 것입니다.)

 

자신이 작성한 메소드와 클래스를 다른 사람이 상속 받아서 사용하지 못하게 금지하고 싶을 때 이용하시면 좋을 것 같습니다.

 

 

Posted by maze1008
,