Programming Language/Java

컬렉션(Collection) (2) - 제네릭(Generic), HashSet, HashMap, Properties, 정렬

Ma_Sand 2022. 3. 17. 21:43
반응형

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

 

[Java/Short] Array, ArrayList 정렬(Sort) 방법

해당 페이지에서는 자주 사용하는 개발 패턴으로 “Array, ArrayList의 정렬”하는 방법에 대해서 공유합니다. 1) Array의 정렬 방법 1. 배열의 숫자 정렬 방법 /* * 숫자 배열의 정렬 */ Integer[] sortNumArr1

adjh54.tistory.com

 

반응형