1. 제네릭(Generic) <E>
: 컬렉션 안에서 다룰 타입들을 미리 지정해준다. ex) <Music>, <String>, <Integer> 등
객체를 형변환할 필요가 없으며 사용하고 싶은 타입만 지정해주면 된다.
⇒ 제네릭을 <Music>으로 지정하면 반환되는 객체(Object)는 Music이 된다.
⇒ 별도의 제네릭을 제시하지 않고 컬렉션 객체를 생성하면 기본 타입이 Object이다.
(1) 제네릭을 사용하는 이유
① 저장할 타입에 제한을 두기 위해서 사용한다.
② 매번 형변환하는 절차를 없애기 위해 사용한다.
(2) 컬렉션 생성 시 제네릭을 설정하는 형식
ArrayList<E> list = new ArrayList<E>();
(3) 예시
ArrayList<Integer> list = new ArrayList<Integer>();
// 값을 추가하는 방법
// 1)
list.add(1);
// 2)
list.add(new Integer(2));
// 3)
Integer i = new Integer(3);
list.add(i);
Integer i2 = new Integer(4);
list.add(i2);
System.out.println(list);
// 결과값: [1, 2, 3, 4]
// 숫자를 지정 삭제하기
list.remove(i2);
System.out.println(list);
// 결과값: [1, 2, 3]
ArrayList<Music> list = new ArrayList<>();
// 앞에서 제네릭 타입을 지정했으면 뒤에는 안 적어도 된다.
list.add(new Music("Next Level", "에스파"));
list.add(new Music("사랑했나봐", "윤도현"));
list.add(new Music("톰보이", "(여자)아이들"));
System.out.println(list);
// 결과값: [Music [title=Next Level, artist=에스파], [title=사랑했나봐, artist=윤도현]
// , [title=톰보이, artist=(여자)아이들]]
list.remove(1); // 1번 인덱스 삭제
System.out.println(list);
// 결과값: [Music [title=Next Level, artist=에스파], [title=톰보이, artist=(여자)아이들]]
(4) 제네릭 Music 지정 전후
① 제네릭 Music 지정 전
: 반환 타입이 Object이므로 Music으로 강제 형변환해야 한다.
for(Object o : list) {
System.out.println(((Music)o).getTitle())
}
② 제네릭 Music 지정 후
: 반환 타입이 Music이므로 강제 형변환하지 않아도 된다.
for(Music m : list){
System.out.println(m.getTitle());
}
2. HashSet
: 값만 저장하고, index 개념이 없어서 저장 순서가 유지되지 않으며, 중복값이 없다.
(1) 표현법
// 표현법
HashSet 이름 = new HashSet();
// 제네릭 설정 표현법
HashSet<E> 이름 = new HashSet<>();
(2) 제네릭에 Student 객체를 넣어 생성하기
HashSet<Student> hs = new HashSet<>();
hs.add(new Student("김영희", 17, 95));
hs.add(new Student("최철수", 18, 82));
hs.add(new Student("이호송", 19, 75));
hs.add(new Student("황송이", 18, 100));
Student s1 = new Student("황송이", 18, 100);
// 새로운 객체를 생성했기 때문에 위의 hs.add()와 주소값이 다르다.
Student s2 = s1;
hs.add(s1);
hs.add(s2);
System.out.println(hs);
// 결과값: 황송이라는 중복값은 제외되고 값들이 섞여서 출력된다.
** HashSet은 값이 추가될 때마다 equals()와 hashCode()로 비교한 후 둘다 결과가 true이면
동일 객체로 판단한다.
- equals(): 현재 객체의 주소값을 비교하여 결과를 반환한다.
- hashcode(): 현재 객체의 주소값을 10진수화하여 반환한다.
** Student 클래스에서 equals()를 오버라이딩 한다면,
- equals(): 각 필드값이 모두 일치하면 true를, 일치하지 않으면 false를 반환한다.
- hashCode(): 각 필드값을 모두 더하여 문자열로 만들고 이를 hashCode해서 반환한다.
(필드값1+필드값2+...).hashCode()
(3) HashSet에 있는 값들을 전부 출력하는 방법 세 가지
① 반복문 -> 인덱스 개념이 없으므로 향상된 for문으로 출력하기
for(Student s : hs) {
System.out.println(s);
}
② HashSet을 ArrayList에 담아서 출력하기
// 1) Student 객체의 ArrayList를 생성하기
ArrayList<Student> list = new ArrayList<>();
// 2) hs에 있는 값들을 list에 전부 추가하기
list.addAll(hs);
for(int i = 0; i < list.dize(); i++) {
System.out.println(list.get(i));
}
// 2-1. 방법2의 1)과 2)를 합쳐서 출력하기
ArrayList<Student> list2 = new ArrayList<>(hs);
for(int i = 0; i < list2.size(); i++) {
System.out.println(list2.get(i));
}
③ Iterator(반복자)를 사용하여 출력하기
: iterator()는 list와 set에서 사용할 수 있고 Map에서는 사용할 수 없다.
Iterator<Student> it = hs.iterator();
while(it.hasNext()) { // hasNext(): 뽑아낼 다음 값이 있는지 확인하여 있으면 true, 없으면 false
System.out.println(it.next()); // next(): 다음 값을 출력한다.
}
3. HashMap
: 저장 순서가 유지되지 않으며, key값은 중복되지 않지만 value값은 중복이 가능하다.
기존 key값에 value값을 넣으면 덮어쓰기가 된다.
(1) 표현법
HashMap<E1, E2> 이름 = new HashMap<>();
(2) 제네릭에 String 타입 객체와 Integer 객체를 넣어 생성하기
HashMap<String, Integer> hm = new HashMap<>();
// 1. put(K key, V value) - Map 공간에 key+value
hm.put("December", 12);
hm.put("July", 7);
hm.put("November", 11);
hm.put("March", 11);
hm.put("April", 5);
hm.put("April", 4);
System.out.println(hm);
// 결과값: {November=11, July=7, April=4, December=12, March=11}
// hashSet과 마찬가지로 순서는 유지되지 않는다.
// key값은 중복을 허용하지 않으므로 April이라는 key값은 5에서 4라는 value값으로 덮어쓰기되었다.
// value값은 중복을 허용하므로 value값이 11인 key값 November과 March는 그대로 출력되었다.
// 2. get(Object key)를 사용하여 key로 value를 뽑아내기
System.out.println(hm.get("December");
// 결과값: 12
// 3. size()를 사용하여 크기 알아내기
System.out.println(hm.size());
// 결과값: 5
// 4. replace(K key, V value)를 사용하여 value값을 변경하기
hm.replace("March", 3);
System.out.println(hm);
// 결과값: {November=11, July=7, April=4, December=12, March=3}
// 4-1. 저장돼있지 않은 key값을 replace하기
hm.replace("January", 1);
System.out.println(hm);
// 이땐 hm에 변경할 해당 key값이 없으므로 결과값에 아무런 변화가 없다.
// 5. remove(Object key)를 사용하여 값을 삭제하기
hm.replace("December");
System.out.println(hm);
// 결과값: {November=11, July=7, April=4, March=3}
// 해당 key와 value를 모두 삭제한다.
(3) put()에 더 많은 value값을 입력하고 싶을 때
: 클래스를 새로 생성하여 value값에 들어갈 생성자를 생성한 후 해당 클래스와 연결한다.
HashMap<String, Food> hm2 = new HashMap<>();
// key: 음식 이름, value: 판매처, 가격
hm2.put("떡볶이", new Food("분식집", 3000));
hm2.put("가츠동", new Food("일식집", 6500));
hm2.put("파스타", new Food("양식집", 11000));
System.out.println(hm2);
// 결과값: {가츠동=Food [sell=일식집, price=6500], 떡볶이=Food [sell=분식집, price=3000]
// , 파스타=Food [sell=양식집, price=11000]}
** List와 Set, Map의 사용하는 메소드 구별
- List와 Set에서만 사용하는 메소드: add(), iterator()
- Map에서만 사용하는 메소드: put()
(4) HashMap에 있는 값들에 순차적으로 접근하기
: Map을 Set으로 변경하여 iterator()로 접근하면 된다.
이때, key값과 value값을 따로 모아야 한다.
① 순서1. keySet()을 사용하여 Set에 HashMap의 key값만 모아 담는다.
Set<String> keySet = hm2.keySet();
System.out.println(keySet);
// 결과값: [떡볶이, 가츠동, 파스타]
// Map의 key값들이 keySet에 담긴다.
② 순서2. 모아놓은 keySet을 Iterator로 접근한다.
Iterator<String> it = keySet.iterator();
③ 순서3. 반복문으로 Iterator를 출력한다.
// 방법1. key값을 하나 하나 접근할 땐 next()로 뽑아낸다.(key값'만' 뽑아낸다. value는 X)
while(it.hasNext()) {
System.out.println(it.next());
}
// 결과값: 떡볶이
// 가츠동
// 파스타
// 방법2. key값과 value값 모두 뽑을 땐 next()로 key값 하나 읽고 get()을 사용하여 해당 key값으로
// value값을 뽑아낸다.
while(it.hasNext()) {
String key = it.next();
Food fValue = hm2.get(key);
System.out.println(key + "=" + fValue);
}
// 결과값: 가츠동=Food [sell=일식집, price=6500]
// 떡볶이=Food [sell=분식집, price=3000]
// 파스타=Food [sell=양식집, price=11000]
** 향상된 for문으로 값을 뽑아내기
- for(반환받을타입 이름 : 반복할 collection 또는 배열) {}
int count = 0;
for(String key : keySet) {
count++;
System.out.println(count + ". " + key);
Food foodValue = hm2.get(key);
System.out.println(foodValue);
}
// 결과값: 1. 떡볶이
// Food [sell=분식집, price=3000]
// 2. 가츠동
// Food [sell=일식집, price=6500]
// 3. 파스타
// Food [sell=양식집, price=11000]
(5) entrySet()를 사용하여 key값과 value값을 한번에 담기
① 순서1. Map에 있는 key와 value를 Entry라는 형식으로 Set에 담는다.
Set<Entry<Key, Value>> 이름 = 해쉬맵이름.entrySet();
Set<Entry<String, Food>> entrySet = hm2.entrySet();
② 순서2. 향상된 for문으로 뽑아낸다.
for(Entry<String, Food> en : entrySet) {
System.out.println(en.getKey() + "=" + en.getValue());
}
// 결과값: 1. 떡볶이
// Food [sell=분식집, price=3000]
// 2. 가츠동
// Food [sell=일식집, price=6500]
// 3. 파스타
// Food [sell=양식집, price=11000]
4. Properties
: Key와 Value를 String 타입으로 설정한 Map 계열 컬렉션이다.
(1) 표현법
Properties 객체명 = new Properties(); // 제네릭은 지정하지 않는다.
(2) 용도
: 파일(*.properties)을 입출력(IO)하기 위해 사용한다.
- .properties라는 확장자를 사용한다. 이는 자주 변경되지 않는 설정 파일이나 해당 프로그램이 가져야할
설정 정보들을 담는다.
// 출력
Properties prop = new Properties();
// Map 계열이라 동일한 key값에 다른 value값을 입력하면 덮어쓰기된다.
prop.put("List", "ArrayList");
prop.put("Set", "HashSet");
prop.put("Map", "HashMap");
prop.put("Set", "LinkedHashSet");
// Properties만 사용할 수 있는 setProperty() (put()과 같은 용도)
prop.setProperty("List", "ArrayList");
prop.setProperty("Set", "HashSet");
prop.setProperty("Map", "HashMap");
// 입력
Properties inputProp = new Properties();
try {
// 출력
// store(): 바이트 스트림으로 저장된 정보를 파일에 출력 저장할 때 쓰이는 메소드
prop.store(new FileOutputStream("proptest.properties"), "Properties Test");
// 입력
// load(): 바이트 스트림으로 저장된 파일의 내용을 읽어와 Properties 객체에 저장하는 메소드
inputProp.load(new FileInputStream("proptest.properties"), "");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
5. 정렬
https://adjh54.tistory.com/121