Java의 정석 3판을 보며 공부한 내용을 정리하였습니다.
남궁성님께 많이 배우고 있습니다.
HashTable과 HAshMap의 관계는 Vector와 ArrayList의 관계와 같다!
Vector를 예전에 많이 썼고 앞으로는 ArrayList를 사용하는게 좋은 것처럼.
HashTable보다 HashMap을 사용하는 것이 좋다.
HashMap은 Map을 구현했으므로 Map의 특징을 갖고 있다.
Key는 유일해야 한다.
Value는 중복을 허용한다.
Key와 Value를 묶어서 하나의 데이터로 저장
Hashing을 사용하므로 많은 양의 데이터를 검색하는데 뛰어난 성능을 보인다.
다음은 HshMap이 데이터를 저장하는 실제 소스의 일부이다.
public class HashMap extends AbstractMap implements Map, Cloneable, Serializable
{
transient Entry[] table;
...
static class Entry implements Map.Entry {
final Object key;
Object value;
...
}
}
HashMap은 내부에 Entry라는 내부 클래스를 정의한다.
이것은 무결성적인 측면에서 더 바람직하다.
Entry[] table;
class Entry {
Object key;
Object value;
}
HashMap은 Key와 Value를 각각 Object 타입으로 저장해서 어떤 객체도 저장할 수 있지만 Key는 주로 String을 대문자 또는 소문자로 통일해서 사용한다.
public static void main(String[] args) {
HashMap map = new HashMap();
map.put("myId", "1234");
map.put("asdf", "1111");
map.put("asdf", "1234");
Scanner s = new Scanner(System.in);
while(true) {
System.out.println("id와 password입력 ");
System.out.print("id 입력 : ");
String id = s.nextLine().trim();
System.out.print("password : ");
String password = s.nextLine();
System.out.println();
if(!map.containsKey(id)) {
System.out.println("입력하신 id는 존재하지 않습니다. 다시 입력해주세요.");
continue;
}
if(!(map.get(id)).equals(password)) {
System.out.println("비밀번호가 일치하지 않습니다. 다시 입력해주세요");
}
else {
System.out.println("id와 비밀번호가 일치합니다.");
break;
}
}
}
출력결과 :
id와 password입력
id 입력 : asdf
password : 1111
비밀번호가 일치하지 않습니다. 다시 입력해주세요
id와 password입력
id 입력 : asdf
password : 1234
id와 비밀번호가 일치합니다.
asdf 키에 처음에는 1111 로 비밀번호를 설정하였고
두번째는 1234로 설정하였다.
이 때, 1234가 비밀번호인 걸 확인할 수 있고
이것은 put을 했을 때 같은 키가 있다면 값을 덮어씌운다는 것을 알 수 있다.
3개의 데이터 쌍을 저장했지만, 실제로는 2개의 데이터 쌍만 저장된 것이다.
HashTable은 key나 value로 null을 허용하지 않지만,
HashMap은 허용한다.
그래서 'map.put(null, null);' 이나 'map.get(null);'이 가능하다
public static void main(String[] args) {
HashMap map = new HashMap();
map.put("김자바", new Integer(100));
map.put("이자바", new Integer(100));
map.put("강자바", new Integer(80));
map.put("안자바", new Integer(90));
Set set = map.entrySet();
Iterator it = set.iterator();
while(it.hasNext()){
Map.Entry e = (Map.Entry)it.next();
System.out.println("이름 : "+e.getKey()+e.getValue());
}
set = map.keySet();
System.out.println("참가자 명단 : "+set);
Collection values = map.values();
it = values.iterator();
int total = 0;
while(it.hasNext()) {
Integer i = (Integer)it.next();
total += i.intValue();
}
System.out.println("총점 : "+total);
System.out.println("평균 : "+(float)total/set.size());
System.out.println("최고점수 : "+Collections.max(values));
System.out.println("최저점수 : "+Collections.min(values));
}
출력 결과 :
이름 : 안자바90
이름 : 김자바100
이름 : 강자바80
이름 : 이자바100
참가자 명단 : [안자바, 김자바, 강자바, 이자바]
총점 : 370
평균 : 92.5
최고점수 : 100
최저점수 : 80
entrySet()을 이용하여 키와 값을 함께 읽기
keySet()이나 value()를 이용해서 따로 읽기
두가지 기본 메서드의 기능을 확인할 수 있다.
static HashMap phoneBook = new HashMap();
public static void main(String[] args) {
addPhoneNo("친구", "이자바", "010-111-1111");
addPhoneNo("친구", "김자바", "010-222-2222");
addPhoneNo("친구", "김자바", "010-333-3333");
addPhoneNo("회사", "김대리", "010-444-4444");
addPhoneNo("회사", "김대리", "010-555-5555");
addPhoneNo("회사", "박대리", "010-666-6666");
addPhoneNo("회사", "이과장", "010-777-7777");
addPhoneNo("세탁", "010-888,8888");
printList();
}
// 그룹에 전화번호 추가
static void addPhoneNo(String groupName, String name, String tel) {
addGroup(groupName);
HashMap group = (HashMap)phoneBook.get(groupName);
group.put(tel, name); // 이름은 중복될 수 있으니 전화번호 key로!
}
// 그룹을 추가
static void addGroup(String groupName) {
if(!phoneBook.containsKey(groupName)) {
phoneBook.put(groupName, new HashMap());
}
}
static void addPhoneNo(String name, String tel) {
addPhoneNo("기타", name, tel);
}
// 전화번호부 전체 출력
static void printList() {
Set set = phoneBook.entrySet();
Iterator it = set.iterator();
while(it.hasNext()) {
Map.Entry e = (Map.Entry)it.next();
Set subSet = ((HashMap)e.getValue()).entrySet();
Iterator subIt = subSet.iterator();
System.out.println(" * "+e.getKey()+"["+subSet.size()+"]");
while(subIt.hasNext()) {
Map.Entry subE = (Map.Entry)subIt.next();
String telNo = (String)subE.getKey();
String name = (String)subE.getValue();
System.out.println(name+" "+telNo);
}
System.out.println();
}
}
출력 결과 :
* 기타[1]
세탁 010-888,8888
* 친구[3]
이자바 010-111-1111
김자바 010-222-2222
김자바 010-333-3333
* 회사[4]
이과장 010-777-7777
김대리 010-444-4444
김대리 010-555-5555
박대리 010-666-6666
HashMap은 데이터와 키 값을 모두 Object로 저장하기 때문에!
HashMap의 값으로 HashMap을 다시 저장할 수 있다!
public static void main(String[] args) {
String[] data = {"A", "K", "A", "K", "D", "K", "A", "K", "K", "K", "Z", "D"};
HashMap map = new HashMap();
for(int i=0; i<data.length; i++) {
if(map.containsKey(data[i])) {
Integer value = (Integer)map.get(data[i]);
map.put(data[i], new Integer(value.intValue() +1));
}
else {
map.put(data[i], new Integer(1));
}
}
Iterator it = map.entrySet().iterator();
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
int value = ((Integer)entry.getValue()).intValue();
System.out.println(entry.getKey()+" : "+ printBar('#', value) +" "+value);
}
}//main
public static String printBar(char ch, int value) {
char[] bar = new char[value];
for(int i=0; i<bar.length; i++) {
bar[i] = ch;
}
return new String(bar); // String(char[] chArr)
}
출력 결과 :
A : ### 3
D : ## 2
Z : # 1
K : ###### 6
문자열을 하나씩 읽어서 HashMap에 키로 저장하고 값을 1로 저장
HashMap에 같은 문자열이 키로 저장되어 있는지 확인하고 같은 문자열이면 1을 증가시킨다.
한정된 범위 내에 있는 순차적인 값들의 빈도수는 배열을 이용하지만,
이처럼 한정되지 않은 범위의 비순차적인 값들의 빈도수는 HashMap을 이용하여 구할 수 있다.