1. JCF - HashMap과 Hashtable 컬렉션 클래스
[HashMap과 Hashtable 설명]
1) Map 인터페이스를 구현한 컬렉션 클래스
2) Entry == Key + Value 한쌍 -> 하나의 데이터로 저장
3) Hashtable 보다 HashMap 사용을 권장, HashMap이 새로나온 버전 -> 사용방법은 동일
4) Hash : 해싱을 사용하기 때문에 '많은 양의 데이터를 검색할 때' 성능이 뛰어나다.
5) Vector(동기화 처리 O) 와 ArrayList(동기화 처리 X) 관계와 비슷하다.
6) Key 중복허용 X, Value 중복허용 O
[해싱과 해시함수]
- 해싱 : 해시함수를 이용해서 데이터를 해시테이블에 저장하고 검색하는 기법
- 해시함수 : 데이터가 저장되어 있는 곳을 알려주는 함수
데이터 위치를 알려주기 때문에 대량의 데이터 중에서 원하는 데이터를 빠르게 찾을 수 있다.
- 해싱에서 사용하는 자료구조는 배열과 링크드 리스트의 조합으로 되어 있다.
- 환자 데이터를 가져오기 위해서 주민등록번호 앞자리인 생년을 기준으로 데이터를 분류해서 배열에 담았고 xx년대 환자의 정보를 링크드 리스트에 담은 것이 아래 그림으로 표현할 수 있다.
[HashMap의 생성자와 메서드]
코드)
HashMap 생성한 뒤 put으로 key, value 추가
[Hashtable 사용 예제]
public class Ex02 {
public static void main(String[] args) {
// Key = 팀명, value = 팀원들(ArrayList)
Hashtable<String, ArrayList<Member>> ht = new Hashtable(); // 뒤에 있는 <String, ArrayList<Member>> 지워도 된다.
ArrayList<String> tnList = new ArrayList(); // 팀명을 가지고 있는 리스트
tnList.add("해조");
tnList.add("돈조");
tnList.add("놔조");
ArrayList<Member> team1 = new ArrayList();
team1.add(new Member("유재석", 90));
team1.add(new Member("김기수", 78));
team1.add(new Member("도경환", 66));
ArrayList<Member> team2 = new ArrayList();
team2.add(new Member("안정환", 89));
team2.add(new Member("김숙", 99));
// team2.add(new Member("마동석", 65));
ArrayList<Member> team3 = new ArrayList();
team3.add(new Member("손흥민", 65));
team3.add(new Member("김태우", 28));
team3.add(new Member("황의조", 65));
// key팀명 value 팀원들(ArrayList)
ht.put(tnList.get(0), team1);
ht.put(tnList.get(1), team2);
ht.put(tnList.get(2), team3);
/*
*
// [문제] 2팀의 팀원들 정보를 출력
ArrayList<Member> list = ht.get("해조");
Iterator<Member> ir = list.iterator();
while (ir.hasNext()) {
Member m = (Member) ir.next();
System.out.println(m);
}
*/
// [문제] 모든 조가 아래와 같이 출력
// 1조 - 해조
// Member [name=유재석]
// Member [name=김기수]
// Member [name=도경환]
// [문제점파악] 출력 팀의 순서가 맞지 않다. -> 나중에 다시 해결하기로!
Set<Entry<String, ArrayList<Member>>> es = ht.entrySet();
Iterator<Entry<String, ArrayList<Member>>> ir = es.iterator();
int no = 1;
while (ir.hasNext()) {
Entry<String, ArrayList<Member>> entry = ir.next();
String teamName = entry.getKey();
ArrayList<Member> memberList = entry.getValue();
System.out.printf("%d조 - %s(%d명)\n", no++, teamName, memberList.size());
Iterator<Member> ir2 = memberList.iterator();
while (ir2.hasNext()) {
Member m = (Member) ir2.next();
System.out.println("\t\t" + m);
}
} // while
} // main
} // class
// 팀원의 정보 클래스
class Member {
String name;
int score;
// String job; // 직급을 주는 변수 팀장, 팀원, 기술고문
public Member(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "Member [name=" + name + ", score=" + score + "]";
}
} // Member class
[HashMap 사용예제] 해당 그룹에 연락처 추가하기
main() 메서드)
printList 메서드)
addPhoneNo와 addGroup 메서드)
[HashMap 사용예제] 파일을 읽어와서 한 문자 확인 후 갯수와 막대그래프 그리기
public class Ex04 {
// 파일을 읽어서 A 12, 막대그래프 ####
public static void main(String[] args) {
String fileName = "days20\\Ex01.java";
String path = String.format("%s\\src\\%s", System.getProperty("user.dir"), fileName);
// A 1++; -> character 문자를 읽어서 Integer에 갯수 만큼 증가
HashMap<Character, Integer> map = new HashMap<>(); // int[] counter = new int[26]; // 대소문자 구분없이 A나 a는 0번 째 인덱스에 집어 넣을 것, Z z 는 [25]
char one;
int code;
try( FileReader fr = new FileReader(path); ) {
while( (code = fr.read()) != -1 ) { // 모든 문자를 다 읽어서 체크
one = (char) code; // 읽어온 문자를 char로 변환해서 one에 넣기
if (map.containsKey(one)) {
map.put(one, map.get(one) + 1);
} else {
map.put(one, 0); // 1
}
} // while
} catch (Exception e) {
e.printStackTrace();
}
Iterator<Entry<Character, Integer>> ir = map.entrySet().iterator();
while (ir.hasNext()) {
Entry<Character, Integer> entry = (Entry<Character, Integer>) ir.next();
System.out.printf("[%c] : %s(%d)\n", entry.getKey(), printBarGraph('*', entry.getValue()),entry.getValue());
}
} // main
public static String printBarGraph(char style, int length) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
sb.append(style);
}
return sb.toString();
} // printBarGraph
} // class
2. JCF - TreeMap 컬렉션 클래스
- 이진 검색 트리의 형태로 키(Key)와 값(Value)의 쌍(entry)으로 이루어진 데이터를 저장
- 검색과 정렬에 적합한 클래스
- 검색 기능은 HashMap 더 뛰어남, 범위검색이나 정렬이 필요한 경우 TreeMap 사용
- SortedMap : Map + 정렬된 기능 => 데이터를 넣으면 자동으로 정렬 되어짐
[TreeMap의 생성자와 메서드]
3. JCF - Properties 컬렉션 클래스***
1) Proterty(속성) -> 속성들을 저장할 때 많이 사용하는 컬렉션 클래스이다.
2) 애플리케이션의 '환경설정'하는 값들을 저장하고 읽기 위한 용도로 주로 사용됨
3) 속성명(Key) = 속성값(Value) 한쌍으로 저장
4) Map 인터페이스를 구현한 컬렉션 클래스
5) Key, Value의 자료형이 모두 String이다. (HashMap<String, String> == Properties 같은 의미)
+ HashMap<String, String>과 차이점은?
- 파일 저장/읽기 할 수 있는 메서드가 Properties에 구현이 되어져 있음(HashMap은 없음)
- 파일명.properties -> Properties 컬렉션 클래스를 사용한 읽기, 쓰기, 저장하는 파일
- store() 메서드 -> 파일 쓰기
- load() 메서드 -> 파일 읽기
[Properties의 생성자와 메서드]
[Properties 컬렉션 클래스로 JDBC 환경설정 값을 파일로 저장하기]
String className = "oracle.jdbc.driver.OracleDriver"; -> DB 연결할 때 필요한 클래스명(fullName)
String url = "jdbc:oracle:thin:@localhost:1521:xe"; -> DB를 연결할 때 필요한 서버
String user = "scott"; -> DB를 연결할 계정(사용자)
String password = "tiger"; -> 계정의 비밀번호
<결과물>
[Properites 컬렉션 클래스로 properties 파일 읽어오기]
1) while문을 사용
2) load() 메서드 사용
[Properties 컬렉션 클래스로 시스템의 속성들 가져오기]
4. JCF - Collections 컬렉션 클래스
- 컬렉션과 관련된 메서드를 제공
- ArrayList(동기화 처리X) VS Vector(동기화 처리O)
- Hashtable(동기화 처리O) VS HashMap((동기화 처리X)새로운 클래스로 사용권장)
- ArrayList와 HashMap은 동기화 처리가 안되어져 있지만, Collections 안의 동기화 처리 메서드를 사용하면된다.
[Collections 컬렉션 클래스의 동기화 관련 메서드]
[사용방법]
5. JCF - 컬렉션 클래스 정리 및 요약
Properites 컬렉션 클래스를 마지막으로.. 컬렉션 프레임웍에 대해서 배웠다.
컬렉션 클래스를 정리한 표는 다음과 같다.
[컬렉션 클래스간의 관계]
[컬렉션 클래스의 특징]
6. 지네릭스(Generics) == 제네릭, 지네릭
1) JDK 1.5부터 도입
JDK 1.7부터는 추정이 가능한 경우 타입을 생략할 수 있음
2) 다양한 타입의 객체들을 다루는 메서드 / 컬렉션 클래스에 [컴파일 시]의 타입 체크(compile-time type check) 해주는 기능(기술) -> 자료형이 정해지지 않고 컴파일시 자료형을 지정
3) 장점
ㄱ. 객체 타입의 안정성 제공
ㄴ. 형변환의 번거로움을 줄이고(형변환 생략 가능) 코드가 간결해진다.
[지네릭스 설명]
int 타입의 값을 가지는 박스, double 타입의 값을 가지는 박스, boolean 타입의 값을 가지는 박스
이렇게 3개 값을 가지는 박스를 만들기 위해서는 int, double, boolean 타입의 멤버변수를 가지고 있는 Box 클래스를 각각 자료형에 맞게 선언을 해야한다.
public class Ex09 {
public static void main(String[] args) {
/*
// int Box 클래스
Box box1 = new Box(100);
int value = box1.getValue();
System.out.println(value);
*/
/*
// double Box 클래스
Box box1 = new Box(3.14);
double value = box1.getValue();
System.out.println(value);
*/
/*
// boolean Box 클래스
Box box1 = new Box(true);
boolean value = box1.getValue();
System.out.println(value);
*/
} // main
} // class
/*
class Box{
// field
private boolean value;
// constructor
public Box(boolean value) {
this.value = value;
}
// getter
public boolean getValue() {
return value;
}
// setter
public void setValue(boolean value) {
this.value = value;
}
} // Box
*/
/*
class Box{
// field
private double value;
// constructor
public Box(double value) {
this.value = value;
}
// getter
public double getValue() {
return value;
}
// setter
public void setValue(double value) {
this.value = value;
}
} // Box
*/
/*
class Box{
// field
private int value;
// constructor
public Box(int value) {
this.value = value;
}
// getter
public int getValue() {
return value;
}
// setter
public void setValue(int value) {
this.value = value;
}
} // Box
위와 같이 클래스를 3개 선언하지 않고 Object 클래스(템플릿 클래스) 하나를 선언하면 조금 더 쉽게 원하는 값을 박스에 넣을 수 있다. 하지만, 원하는 타입의 자료형으로 형변환을 해주어야 한다는 번거로움이 있다.
main() 메서드)
형변환을 생략하고 코드가 간결해지는 제네릭 클래스를 사용하면 훨씬 쉬워진다.
클래스를 제네릭 클래스로 변경하기 위해서 클래스 명 옆에 <T>를 붙이면 된다.
그리고 위 템플릿 클래스에 Object를 모두 T로 바꿔준다.
[지네릭스의 용어]
1) T : 타입 변수 또는 타입 매개변수(T는 타입문자)
E는 Element, K는 Key, V는 Value ...
기호의 종류만 다를 뿐 '임의의 참조형 타입'을 의미한다는 것은 모두 같다.
2) Box<T> : 제네릭 클래스 -> T의 Box 클래스 또는 T Box 클래스라고 읽는다.
"T의 Box 제네릭 클래스"
3) Box : 원시타입(raw type)
[지네릭 클래스의 객체 생성과 사용 예제]
* Apple 클래스의 implements Eatable 은 제한된 지네릭스 클래스 내용 설명할 때 사용
- 생성된 Box<T> 객체에 add() 메서드로 객체를 추가할 때, 대입된 타입과 다른 타입의 객체는 추가할 수 없다.
Box2<Apple> appleBox = new Box2<Apple>();
appleBox.add(new Apple()); -> 가능
appleBox.add(new Grape()); -> 에러, Box2<Apple>에는 Apple 객체만 추가 가능
- 만약, 타입 T가 Fruit인 경우 Fruit의 자식들은 add() 메서드의 매개변수가 될 수 있다.
Box2<Fruit> furitBox = new Box2<>();
furitBox.add(new Fruit());
furitBox.add(new Apple());
furitBox.add(new Grape());
[제한된 지네릭스 클래스]
- 지네릭스 클래스에는 static 필드, 메서드를 선언할 수 없다. static은 객체를 생성하기 전에 호출 가능한 것인데 지네릭스는 컴파일시 타입을 결정함으로 서로 공존할 수 X
class Box<T>{
static 필드; -> 에러 발생
static 메서드(); -> 에러 발생
}
- T[] 배열; -> 배열 선언 사용 가능
new T[3]; -> 배열 생성 사용 불가능
- 지네릭스 타입에 'extends'를 사용하면, 특정 타입의 자식들만 대입할 수 있게 제한할 수 있음
> extends 사용전에는 FruitBox에 모든 타입을 담을 수 있음
FruitBox<Toy> furitBox = new FruitBox<>();
furitBox.list.add(new Toy()); -> 과일박스에 장난감을 담을 수 있음
class FruitBox<T>{
ArrayList<T> list = new ArrayList<T>();
} // FruitBox
> extends 사용 후 FruitBox는 Fruit 클래스의 자식들만 담을 수 있다는 제한이 생김
// 제한된 제네릭 클래스
// 과일 클래스를 물려받은 자식이면서 Eatable 인터페이스를 구현한 클래스 타입을 사용하겠다.
class FruitBox<T extends Fruit>{ // <T extends Fruit> : Fruit에서 물려받은 어떤 타입이라도 사용을 가능하도록 하겠다.
ArrayList<T> list = new ArrayList<T>();
} // FruitBox
> 클래스가 아닌 인터페이스를 구현해야 한다는 제약이 필요하다면, extends 사용(implements 사용X)
> Fruit의 자식이면서 Eatable 인터페이스도 구현해야한다면 & 기호로 연결
interface Eatable{}
// 제한된 제네릭 클래스
// 과일 클래스를 물려받은 자식이면서 Eatable 인터페이스를 구현한 클래스 타입을 사용하겠다.
class FruitBox<T extends Fruit & Eatable>{ // <T extends Fruit> : Fruit에서 물려받은 어떤 타입이라도 사용을 가능하도록 하겠다.
ArrayList<T> list = new ArrayList<T>();
} // FruitBox
// Eatable 인터페이스를 구현한 클래스만 타입으로 지정가능
// Apple 클래스를 Eatable 인터페이스를 구현했기 때문에 가능
FruitBox<Apple> box4 = new FruitBox<>();
> add() 매개변수의 타입 T도 Fruit와 그 자식 타입이 될 수 있다.
FruitBox<Fruit> box = new FruitBox<>();
FruitBox<Apple> appleBox = new FruitBox<>();
FruitBox<Toy> toyBox = new FruitBox<>(); -> 에러, Toy는 Fruit의 자식이 아님
box.list.add(new Apple()); -> Apple이 Fruit의 자식
box.list.add(new Grape()); -> Grape가 Fruit의 자식
코드)
[와일드 카드 == ?]
<? extends T> : 와일드 카드의 상한 제한, T와 그 자식들만 가능
<? super T> : 와일드 카드의 하한 제한, T와 그 부모들만 가능
<?> : 제한 없음, 모든 타입이 가능(<? extens Object> 와 동일)
ArrayList list는 Temp를 담을 수 있고, Vector는 Employee를 담을 수 있는데 new 연산자를 통해서 생성했을 때, Collections <? extends Employee> c -> 와일드 카드로 인하여 Employee와 그 자식들만 가능하다. Temp는 Employee의 자식이므로 담을 수 있는것!
'TIL > Java' 카테고리의 다른 글
[SIST] Java_days28 (0) | 2022.03.29 |
---|---|
[SIST] Java_days27 (0) | 2022.03.28 |
[SIST] Java_days25 (0) | 2022.03.24 |
[SIST] Java_days24 (0) | 2022.03.23 |
[SIST] Java_days23 (0) | 2022.03.22 |