210727 화
Collection
1. Map
1) Map 특징
-Key와 값(멘틀)으로 구성
-키와 값은 모두 객체이다
-키는 중복 저장을 허용하지 않고 값은 중복 저장이 가능하다
-구현 클래스로 HashMap, HashTable, LinkedHashMap, Properties, TreeMap이 있음
2) Map 계열 주요 메소드
(1) 객체 추가
(2) 객체 검색
(3) 객체 삭제
3) Map 계열 클래스
(1) HashMap(동기화 X)
-키 객체는 hashCode()와 equals()를 재정의해 동등 객체가 될 조건을 정해야 함
-키 타입은 hashCode와 equals()메소드가 재정의되어 있는 String타입을 주로 사용
(2) Hashtable(동기화 O)
-스레드 동기화가 된 상태이기 때문에, 복수의 스레드가 동시에 Hashtable에 접근해 객체를 추가, 삭제 하더라도 스레드에 안전 (Thread safe)
package com.kh.chap03_map.part01_hashMap.controller;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import com.kh.chap03_map.part01_hashMap.model.vo.Car;
public class HashMapTest {
/*
* Map계열의 특징 : 키(key)와 값(value)으로 구성 되어 있으며 키와 값은 모두 객체
* 키는 중복 저장 불가(Set 방식), 값은 중복 저장 가능(List방식)
* 중복된 키를 가진 값이 추가될 경우 기존 값에 덮어쓰기 처리 됨
* Map 계열의 종류 : HashMap, HashTable, LingkedHashMap, Properties, TreeMap
* HashMap : key객체는 hashCode, equals를 재정의 해야됨(Set에서처럼 동등 객체 중복 제거를 위해)
* 주로 String을 키 타입으로 사용(이미 hashCode, equals가 오버라이딩 되어 있음)
* HashTable : HashMap의 구버전, 동기화 지원
* LinkedHashMap : HashMap을 상속 받아 구현 된 클래스로 저장 순서가 유지 된다는 차이점만 있음
*/
public void doHashMap() {
HashMap<String, Car> hm = new HashMap<>();
//제네릭스 선언..
// HashMap hm = new HashMap();
//만약 제네릭스 선언이 되어있지 않다면 리턴값이 불명확하게 나온다.. get관련
//List, Set 값 추가시 add()
//1. put(K key, V value) : 지정한 키와 값 객체를 맵에 저장
hm.put("소나타", new Car("현대", 13.3));
hm.put("k5", new Car("기아", 16.1));
hm.put("말리부", new Car("쉐보레", 15.3));
System.out.println(hm);
// {말리부=Car [manufacturer=쉐보레, fuelEfficiency=15.3],
// 소나타=Car [manufacturer=현대, fuelEfficiency=13.3],
// k5=Car [manufacturer=기아, fuelEfficiency=16.1]}
//다른 key에 동등 객체 입력 => 동등 객체도 key값이 다르면 저장 가능
hm.put("아반떼", new Car("현대", 13.3));
System.out.println(hm);
// {말리부=Car [manufacturer=쉐보레, fuelEfficiency=15.3],
// 아반떼=Car [manufacturer=현대, fuelEfficiency=13.3],
// 소나타=Car [manufacturer=현대, fuelEfficiency=13.3],
// k5=Car [manufacturer=기아, fuelEfficiency=16.1]}
//같은 key에 다른 객체 입력 => 같은 key를 입력하면 새롭게 입력한 객체롭 변경됨(덮어쓰기)
hm.put("말리부", new Car("쉐보레", 16.3));
System.out.println(hm);
// {말리부=Car [manufacturer=쉐보레, fuelEfficiency=16.3],
// 아반떼=Car [manufacturer=현대, fuelEfficiency=13.3],
// 소나타=Car [manufacturer=현대, fuelEfficiency=13.3],
// k5=Car [manufacturer=기아, fuelEfficiency=16.1]}
//2. get(K key) : 지정한 키의 값 객체 가져오기
Car c = hm.get("k5");
System.out.println(c);
//답 : Car [manufacturer=기아, fuelEfficiency=16.1]
//3. containsKey(Object key) : key가 있으면 true 반환
// containsValue(Object value) : value가 있으면 true 반환
System.out.println(hm.containsKey("말리부"));
System.out.println(hm.containsValue(new Car("쉐보레", 16.3)));
// true
// false => 왜 false가 나올까?
//List계열에서 contains 메소드로 동등 객체 구분하려고 한다면
//equals 메소드가 해당 클래스에 오버라이딩 되어 있었어야 함..
//오버라이딩 후에는 true값 출력 됨~!
//4. remove(K key) : 해당 키 값의 인스턴스 삭제
hm.remove("아반떼");
System.out.println(hm);
//아반떼 삭제되었음
// {말리부=Car [manufacturer=쉐보레, fuelEfficiency=16.3],
// 소나타=Car [manufacturer=현대, fuelEfficiency=13.3],
// k5=Car [manufacturer=기아, fuelEfficiency=16.1]}
//size(), clear(), isEmpty() => 동일한 사용법이므로 생략하게뜸ㅎㅎ
System.out.println("===================================================");
//Map에 엘리먼트 접근하기
//1. values() : 모든 values를 Collection에 담아 반환
System.out.println(hm.values());
//Car [manufacturer=쉐보레, fuelEfficiency=16.3],
//Car [manufacturer=현대, fuelEfficiency=13.3],
//Car [manufacturer=기아, fuelEfficiency=16.1]]
//Map은 Key, value를 pair로 저장하고 있기 때문에 iterator() 호출 불가
//keySet(), entrySet()과 같은 메소드를 통해서 Set형태로 키 또는 엔트리 값을 얻어와서
//iterator 호출해서 사용
//2. keySet
//2_1. keySet + Iterator
Set<String>keySet = hm.keySet();
//지금 set안에 key값이 들어가있다고 생각하면 됨
Iterator<String> it = keySet.iterator();
while(it.hasNext()) {
String key = it.next();
System.out.printf("키 : %s, 값 : %s\n", key, hm.get(key));
// 키 : 말리부, 값 : Car [manufacturer=쉐보레, fuelEfficiency=16.3]
// 키 : 소나타, 값 : Car [manufacturer=현대, fuelEfficiency=13.3]
// 키 : k5, 값 : Car [manufacturer=기아, fuelEfficiency=16.1]
}
System.out.println();
//2_2. keySet + for each
for(String key : hm.keySet()) {
System.out.printf("키 : %s, 값 : %s\n", key, hm.get(key));
// 키 : 말리부, 값 : Car [manufacturer=쉐보레, fuelEfficiency=16.3]
// 키 : 소나타, 값 : Car [manufacturer=현대, fuelEfficiency=13.3]
// 키 : k5, 값 : Car [manufacturer=기아, fuelEfficiency=16.1]
}
System.out.println();
//3. entrySet : 모든 entry 객체(key + value)를 set에 담아서 반환
//3_1. entrySet + Iterator
Set<Entry<String, Car>> entrySet = hm.entrySet();
Iterator<Entry<String, Car>> it2 = entrySet.iterator();
while(it2.hasNext()) {
Entry<String, Car> entry = it2.next();
System.out.printf("키 : %s, 값 : %s\n", entry.getKey(), entry.getValue());
// 키 : 말리부, 값 : Car [manufacturer=쉐보레, fuelEfficiency=16.3]
// 키 : 소나타, 값 : Car [manufacturer=현대, fuelEfficiency=13.3]
// 키 : k5, 값 : Car [manufacturer=기아, fuelEfficiency=16.1]
}
System.out.println();
//3_2. entrySet + for each
for(Entry<String, Car> entry : hm.entrySet()) {
System.out.printf("키 : %s, 값 : %s\n", entry.getKey(), entry.getValue());
// 키 : 말리부, 값 : Car [manufacturer=쉐보레, fuelEfficiency=16.3]
// 키 : 소나타, 값 : Car [manufacturer=현대, fuelEfficiency=13.3]
// 키 : k5, 값 : Car [manufacturer=기아, fuelEfficiency=16.1]
}
}
}
package com.kh.chap03_map.part01_hashMap.model.vo;
public class Car {
private String manufacturer; //제조사
private double fuelEfficiency; //연비
public Car() {}
public Car(String manufacturer, double fuelEfficiency) {
super();
this.manufacturer = manufacturer;
this.fuelEfficiency = fuelEfficiency;
}
public String getmanufacturer() {
return manufacturer;
}
public double getFuelEfficiency() {
return fuelEfficiency;
}
public void setmanufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public void setFuelEfficiency(double fuelEfficiency) {
this.fuelEfficiency = fuelEfficiency;
}
@Override
public String toString() {
return "Car [manufacturer=" + manufacturer + ", fuelEfficiency="
+ fuelEfficiency + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(fuelEfficiency);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + ((manufacturer == null) ? 0 : manufacturer.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Car other = (Car) obj;
if (Double.doubleToLongBits(fuelEfficiency)
!= Double.doubleToLongBits(other.fuelEfficiency))
return false;
if (manufacturer == null) {
if (other.manufacturer != null)
return false;
} else if (!manufacturer.equals(other.manufacturer))
return false;
return true;
}
}
package com.kh.chap03_map.part01_hashMap.run;
import com.kh.chap03_map.part01_hashMap.controller.HashMapTest;
public class Run {
public static void main(String[] args) {
HashMapTest ht = new HashMapTest();
ht.doHashMap();
}
}
(3) TreeSet과 TreeMap
: 검색 기능을 강화시킨 컬렉션으로, 계층 구조를 활용해 이진 트리 자료구조를 구현하여 제공
package com.kh.chap03_map.part02_treeMap.controller;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;
import java.util.Map.Entry;
import com.kh.chap03_map.part02_treeMap.model.comparator.DescString;
import com.kh.chap03_map.part02_treeMap.model.vo.Car;
public class TreeMapTest {
public void doTreeMap() {
//트리 구조로 정렬 기준을 가지고 저장할 경우 사용
TreeMap<String, Car> tm = new TreeMap<String, Car>();
//1. put(K key, V value) : 지정한 키와 값 객체를 맵에 저장
tm.put("소나타", new Car("현대", 13.3));
tm.put("k5", new Car("기아", 16.1));
tm.put("말리부", new Car("쉐보레", 15.3));
System.out.println(tm);
//아까와 저장 순서가 다르다.
//Key값인 String클래스에 오버라이딩 된 compareTo 기준으로
//문자열 오름차순으로 정렬되어 있다.
// {k5=Car [manufacturer=기아, fuelEfficiency=16.1],
// 말리부=Car [manufacturer=쉐보레, fuelEfficiency=15.3],
// 소나타=Car [manufacturer=현대, fuelEfficiency=13.3]}
//다른 key에 동등 객체 입력
//=> 동등 객체도 key값이 다르면 저장 가능
tm.put("아반떼", new Car("현대", 13.3));
System.out.println(tm);
// {k5=Car [manufacturer=기아, fuelEfficiency=16.1],
// 말리부=Car [manufacturer=쉐보레, fuelEfficiency=15.3],
// 소나타=Car [manufacturer=현대, fuelEfficiency=13.3],
// 아반떼=Car [manufacturer=현대, fuelEfficiency=13.3]}
//같은 key에 다른 객체 입력
// => 같은 key를 입력하면 새롭게 입력한 객체로 변경됨(덮어쓰기)
tm.put("말리부", new Car("쉐보레", 15.3));
System.out.println(tm);
// {k5=Car [manufacturer=기아, fuelEfficiency=16.1],
// 말리부=Car [manufacturer=쉐보레, fuelEfficiency=15.3],
// 소나타=Car [manufacturer=현대, fuelEfficiency=13.3],
// 아반떼=Car [manufacturer=현대, fuelEfficiency=13.3]}
System.out.println();
//2. 내림차순 구현 방법
//(1) 사용자 정의 클래스가 정렬 기준인 경우 Comparable 상속 받는 compareTo 변경
//(2) 매개변수 생성자를 통해 재정렬(Wrapper, String 클래스 등)
TreeMap<String, Car> descTm = new TreeMap<>(new DescString());
//1. put(K key, V value) : 지정한 키와 값 객체를 맵에 저장
descTm.put("소나타", new Car("현대", 13.3));
descTm.put("k5", new Car("기아", 16.1));
descTm.put("말리부", new Car("쉐보레", 15.3));
System.out.println(descTm);
// {소나타=Car [manufacturer=현대, fuelEfficiency=13.3],
// 말리부=Car [manufacturer=쉐보레, fuelEfficiency=15.3],
// k5=Car [manufacturer=기아, fuelEfficiency=16.1]}
//복사하지 않고 직접 keySet, entrySet 이용한 순차 출력 연습하기
//tm, descTm
System.out.println();
//2. keySet
//2_1. keySet + Iterator
Set<String> ks = tm.keySet();
//지금 set안에 key값이 들어가있다고 생각하면 됨
Iterator<String> ksit = ks.iterator();
while(ksit.hasNext()) {
String key = ksit.next();
System.out.printf("키 : %s, 값 : %s\n", key, tm.get(key));
// 키 : 말리부, 값 : Car [manufacturer=쉐보레, fuelEfficiency=16.3]
// 키 : 소나타, 값 : Car [manufacturer=현대, fuelEfficiency=13.3]
// 키 : k5, 값 : Car [manufacturer=기아, fuelEfficiency=16.1]
}
System.out.println();
//2_2. keySet + for each
for(String key : tm.keySet()) {
System.out.printf("키 : %s, 값 : %s\n", key, tm.get(key));
// 키 : 말리부, 값 : Car [manufacturer=쉐보레, fuelEfficiency=16.3]
// 키 : 소나타, 값 : Car [manufacturer=현대, fuelEfficiency=13.3]
// 키 : k5, 값 : Car [manufacturer=기아, fuelEfficiency=16.1]
}
System.out.println();
//3. entrySet : 모든 entry 객체(key + value)를 set에 담아서 반환
//3_1. entrySet + Iterator
Set<Entry<String, Car>> es = tm.entrySet();
Iterator<Entry<String, Car>> esit = es.iterator();
while(esit.hasNext()) {
Entry<String, Car> entry = esit.next();
System.out.printf("키 : %s, 값 : %s\n", entry.getKey(), entry.getValue());
// 키 : 말리부, 값 : Car [manufacturer=쉐보레, fuelEfficiency=16.3]
// 키 : 소나타, 값 : Car [manufacturer=현대, fuelEfficiency=13.3]
// 키 : k5, 값 : Car [manufacturer=기아, fuelEfficiency=16.1]
}
System.out.println();
//3_2. entrySet + for each
for(Entry<String, Car> entry : tm.entrySet()) {
System.out.printf("키 : %s, 값 : %s\n", entry.getKey(), entry.getValue());
// 키 : 말리부, 값 : Car [manufacturer=쉐보레, fuelEfficiency=16.3]
// 키 : 소나타, 값 : Car [manufacturer=현대, fuelEfficiency=13.3]
// 키 : k5, 값 : Car [manufacturer=기아, fuelEfficiency=16.1]
}
}
}
package com.kh.chap03_map.part02_treeMap.model.comparator;
import java.util.Comparator;
public class DescString implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
}
package com.kh.chap03_map.part02_treeMap.model.vo;
public class Car {
private String manufacturer; //제조사
private double fuelEfficiency; //연비
public Car() {}
public Car(String manufacturer, double fuelEfficiency) {
super();
this.manufacturer = manufacturer;
this.fuelEfficiency = fuelEfficiency;
}
public String getmanufacturer() {
return manufacturer;
}
public double getFuelEfficiency() {
return fuelEfficiency;
}
public void setmanufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public void setFuelEfficiency(double fuelEfficiency) {
this.fuelEfficiency = fuelEfficiency;
}
@Override
public String toString() {
return "Car [manufacturer=" + manufacturer + ", fuelEfficiency="
+ fuelEfficiency + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(fuelEfficiency);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + ((manufacturer == null)
? 0 : manufacturer.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Car other = (Car) obj;
if (Double.doubleToLongBits(fuelEfficiency)
!= Double.doubleToLongBits(other.fuelEfficiency))
return false;
if (manufacturer == null) {
if (other.manufacturer != null)
return false;
} else if (!manufacturer.equals(other.manufacturer))
return false;
return true;
}
}
package com.kh.chap03_map.part02_treeMap.run;
import com.kh.chap03_map.part02_treeMap.controller.TreeMapTest;
public class Run {
public static void main(String[] args) {
TreeMapTest tt = new TreeMapTest();
tt.doTreeMap();
}
}
1> 정렬(오름차순이 기본)
-TreeSet의 객체와 TreeMap의 key는 저장과 동시에 자동 오름차순 정렬
-숫자(Integer, Double) 타입일 경우 값으로 정렬
-문자열(String) 타입일 경우 유니코드로 정렬
-정렬을 위해 java.lang.Comparable을 구현한 객체 요구. 그러지 않을 경우 ClassCastException 발생
(Integer, Double, String 모두 Comparable 인터페이스를 통해 오름차순이 구현되어 있음)
2> 내림차순을 하고 싶다면? => 따로 구현해야 함
<1> TreeSet, TreeMap 객체 생성 시 매개변수 생성자를 통해 재정렬 가능
ex) TreeSet tSet = new TreeSet(Comparator comparator); TreeMap tMap = new TreeMap(Comparator comparator);
<2> 숫자(Integer, Double), 문자열(String) 타입을 제외한 Comparable을 상속 받는 객체인 경우 compareTo() 메소드의 오버라이딩 부분을 내림차순으로 변경
(4) Properties
-키와 값을 String타입으로 제한한 Map컬렉션
-주로 Properties는 프로퍼티(*.properties)파일을 읽어 들일 때 주로 사용
1> 프로퍼티 파일 특징
- 옵션정보, 데이터베이스 연결정보, 국제화(다국어)정보를 기록하여 텍스트 파일로 활용
- 애플리케이션에서 주로 변경이 잦은 문자열을 저장하여 관리하기 때문에 유지보수를 편리하게 만들어 줌
- 키와 값이 ‘=‘기호로 연결되어 있는 텍스트 파일로 ISO 8859-1 문자셋으로 저장되고, 한글은 유니코드(Unicode)로 변환되어 저장
package com.kh.chap03_map.part03_properties.run;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
import com.kh.chap03_map.part02_treeMap.model.vo.Car;
public class PropertiesTest1 {
public static void main(String[] args) {
Properties prop = new Properties();
//Properties : Map 계열
//원래는 key, value 모두 String 타입만 사용
/*prop.put("소나타", new Car("현대", 13.3));
System.out.println(prop.get("소나타"));
System.out.println(prop);
// Car [manufacturer=현대, fuelEfficiency=13.3]
// {소나타=Car [manufacturer=현대, fuelEfficiency=13.3]}
//properties 파일로 저장
try {
prop.store(new FileOutputStream("car.properties"), "car");
} catch (IOException e) {
e.printStackTrace();
}
//Car cannot be cast to java.lang.String => 오류 발생
//위의 value에 숫자를 넣었기 때문
*
*/
//1. setProperty(String key, String value) : 값 저장
prop.setProperty("List", "ArrayList");
prop.setProperty("Set", "HashSet");
prop.setProperty("Map", "HashMap");
prop.setProperty("Map", "Propeties");
System.out.println(prop);
//답 : {Map=Properies, List=ArrayList, Set=HashSet}
//=> 저장 순서 유지 되지 않으며 키 중복 불가함. 중복 된 키의 경우 값 덮어쓰기.
//2. getProperty(String key) : 값 얻어오기
System.out.println(prop.getProperty("List"));
//3. store(OutputStream os, String comments)
// : 저장 된 정보를 바이트 스트림으로 파일에 출력 저장
// store(Writer writer, String comments)
// : 저장 된 정보를 문자 스트림으로 파일에 출력 저장
// storeToXML(OutputStream os, String comments)
// : 저장 된 정보를 바이트 스트림으로 XML파일에 출력 저장
try {
prop.store(new FileOutputStream("test.properties"), "test");
//text파일이 생김
// #test
// #Tue Jul 27 17:59:51 KST 2021
// Map=Propeties
// List=ArrayList
// Set=HashSet
prop.storeToXML(new FileOutputStream("test.xml"), "test");
//xml파일이 생김
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.kh.chap03_map.part03_properties.run;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
public class PropertiesTest2 {
public static void main(String[] args) {
Properties prop = new Properties();
//4. load(InputStream inStream)
// : 바이트 스트림으로 저장된 파일의 내용을 읽어와서 Properties 객체에 저장
// load(Reader reader)
// : 문자 스트림으로 저장 도니 파일의 내용을 읽어와서 Properties 객체에 저장
// loadFromXML(InputStream inStream)
// : 바이트 스트림으로 저장 된 XML 파일의 내용을 읽어와서 Properties 객체에 저장
try {
//prop.load(new FileInputStream("test.properties"));
// -- listing properties --
// Map=Propeties
// List=ArrayList
// Set=HashSet
prop.load(new FileInputStream("test.xml"));
// -- listing properties --
// <!DOCTYPE=properties SYSTEM "http://java.sun.co...
// <properties>=
// <entry=key="Set">HashSet</entry>
// <comment>test</comment>=
// <?xml=version="1.0" encoding="UTF-8" standa...
// </properties>=
} catch (IOException e) {
e.printStackTrace();
}
//5. list(PrintStream out) : 특정 out stream을 통한 출력
//System.out : 표준 출력 장치로 출력
prop.list(System.out);
}
/*
* Properties 파일을 사용하는 이유?
* => key와 value가 모두 문자열로 제한되어 파일로 저장하고 읽어들이기 쉬움
* => 프로그램에서 변경되는 설정 정보들을 코드안에 작성하지 앟고 별도의 파일에서 관리하여
* 수정사항 발생 시 코드가 아닌 파일 내에서 수정할 수 있도록 함
*
*/
}
*ArrayList, HashMap중요
'웹개발 수업 > JAVA' 카테고리의 다른 글
[Day +27]GUI / Java Swing, 컨테이너, 컴포넌트 (0) | 2021.07.29 |
---|---|
[Day +26]JAVA 2차 시험 & 미니 프로젝트 기획 시작 (0) | 2021.07.28 |
[Day +24]Collection / List, Comparable, Comparator, Set, HashSet, ListIterator, TreeSet (0) | 2021.07.26 |
[Day +23]Collection / 자료구조, List, Set, Map, 제네릭스 (0) | 2021.07.25 |
[Day +22]입출력(IO) / 기본 타입 입출력 보조 스트림, 객체 입출력 보조 스트림, 직렬화, 역직렬화 (0) | 2021.07.22 |