2022-01-20 Generics / Collection

GGAE99·2022년 1월 20일
0

진도

목록 보기
12/43

오늘은 Generics와 Collection을 배웠다. 아니 사실 배우고있다.
국비를 다니는데, 점심시간이라고 노니까 집안일하고, 블로그 포스팅하고, 꼭 해야하는 것들 하고나서 보니까 나중에 알고리즘 공부할 시간이 부족하더라 거의 시작도 못했다... 빨리 시작해서 알고리즘이랑 c++ 더 공부하고 싶어서 점심시간에도 짬을내서 포스팅을 한다. 배운 직후라 더 기억에 잘남기도하다. 어차피 수업 끝나고 추가로 알게된 내용 넣어서 수정해야 할 것 같다.

Generics

Generics는 클래스 내부에서 사용할 데이터타입을 객체생성시 지정하게 해주는 기능이다.
클래스의 객체 생성시 "<>"안에 내부에서 사용할 클래스명을 기입한다. 이때, "<>"안에는 기본자료형을 사용할 수 없다. int같은거.
클래스명<타입>레퍼런스 = new 생성자<타입>();의 형태를 띠고있다.

ArrayList<Velog>list = new ArrayList<Velog>();

한개의 데이터타입에 끝나지않고, 여러 개의 데이터타입을 지정하는것도 가능하다.
기본적인 Generics사용과, 멀티Generics사용에 대해 알아보자.

//Generics 기본 사용
public class GenericEx1<T>{
private T data;
public GenericEx1(){}
public GenericEx1(T data){
this.data = data;
}
public T getData(){ return data; }
public void setData(T data){ this.data = data; }
}


//Generics 멀티 사용
public class GenericEx2<T,E>{
private T data1;
private E data2;
public GenericEx2(){}
public GenericEx2(T data1, E data2){
this.data1 = data1;
this.data2 = data2;
}
public T getData1(){ return data1; }
public void setData1(T data1){ this.data1 = data1; }
public E getData2(){ return data2; }
public void setData2(E data2){ this.data2 = data2; }
}

이렇게 클래스를 선언할 때, "<>"에 임의의 변수를 넣어주고, 이따가 자료형을 저 위치에 넣어주어서, 값을 대입하는 형식으로 사용하는 것 이다.
Generics를 사용의의는 클래스가 객체로 만들어질 때 내부에서 데이터 타입을 지정하는데 있다.
String, int 등 다양한 형태로 지정할 수 있으며, 클래스 형 등으로 지정도 가능하다.
Generics는 여기까지하자. 솔직히 필자는 이거 왜쓰는지 아직은 잘 이해가 안된다. 그래서 설명을 잘 못하겠다. 더 프로그래밍에 익숙해지고, 이것을 쓰는 이유를 알게됐을 때, 다시 오겠다.

Collection

collection은 그래도 확실하게 이해했다. 일단 collection이 뭔지 정리부터 해보자.

  • 메모리상에서 자료를 구조적으로 처리하는 방법을 자료구조라고 함
  • Collection은 자바에서 제공하는 자료구조를 담당하는 프레임워크임
  • 추가, 삭제, 정렬 등의 기능처리가 간단하게 해결되어 자료구조적 알고리즘을 사용자가 별도로 구현할 필요가 없음
  • 저장하는 크기의 제약이 없음
  • 여러 타입을 저장할 수 있음
    객체타입만 저장할 수 있기 때문에, 상속과 다형성을 이용하여 저장해야한다.
    기본자료형을 저장하고 싶을 때에는 Wrapper클래스를 사용한다.

그럼 이제 이걸 쓰는 이유를 알아보자. 그 이유는 배열에 있다.

배열의 단점

  • 한번 크기를 지정하면 변경할 수 없기때문에 할당 시 넉넉한 크기로 할당을 하게되는데, 그러면 메모리가 낭비된다. 이걸 필요에 따라 늘이거나 줄일 수 없다.
  • 배열에 기록된 데이터에 대한 중간위치의 추가, 삭제가 불편하다.
    해야할 경우에는, 수정이 필요한 데이터부터 마지막 데이터까지 하나하나 뒤로 밀어내거나 당겨오는 작업을 진행해야지 가능하다.
  • 한 타입의 데이터만 저장이 가능하다.

이렇게나 배열의 단점이 명확하다.
배열 대신에 List, Set, Map등의 인터페이스를 사용해보자.

List

list

  • 자료들을 순차적으로 나열한 자료구조다.
  • 인덱스로 관리되며, 중복해서 객체 저장이 가능하다.
  • 배열과 가장 유사한 형태를 띄고 있다.
  • 구현 클래스 ArrayList, Vector, LinkedList가 존재한다.

오늘은 이 구현 클래스 중 ArrayList만 살펴본다.
일단 이 ArrayList를 사용할 때, 위에서 배운 Generic을 사용한다. 후에는 그냥 제네릭으로 부르겠다.제네릭을 사용해서 객체를 관리할 타입을 지정해준다.

import java.util.ArrayList;
public class List {
	public void listTest1() {
   	        ArrayList<String> list = new ArrayList<String>();
		System.out.println("리스트의 길이 : "+list.size());//현재 리스트가 사용중인 길이
		list.add("hi"); 		//리스트 제일 뒤에 데이터 추가
		System.out.println("리스트의 길이 : "+list.size());//현재 리스트가 사용중인 길이
    }
}

와 같은 형식으로 사용할 수 있다. 위의 ArrayList list의 형태는 String형이고, "hi"값을 가지고있다. 출력해보면, 리스트의 길이가 1씩 늘어나고있는 것을 볼 수 있다.
for문을 사용해서, list전체를 출력할 수 있다.

for(int i = 0; i<list.size();i++) {
			//리스트에서 데이터를 가져올때 get(번호);
			System.out.println(i+". "+list.get(i));			
		}

이 코드를 사용하면, list에 들어있는 모든 값을 출력한다. list는 다양한 메소드를 가지고있는데, 이 메소드들을 이용하면 list를 마음대로 사용할 수 있을 것 같다고 생각한다.
일단 list에 쓰이는 다양한 메소드들을 살펴보고, 자주 쓰는 내용은 정리해보자.

list method
메소드 // 리턴타입 // 설명
1. 객체 검색 메소드

  • add(E)//boolean//주어진 객체를 맨 끝에 추가
  • add(int index, E element) // void // 주어진 인덱스에 객체 추가
  • addAll(Collection c) // boolean// 주어진 Collection 타임 객체 추가
  • addAll(int index, Collection c) // boolean // 주어진 Collection타입 객체를 주어진 인덱스에 추가
  • set(int index , E element) // Generic // 주어진 인덱스에 저장된 객체를 변경하고 변겅 전 값 리턴
  1. 객체 검색 메소드
  • contains(Object o) // boolean // 주어진 객체가 저장되어 있는지 확인
  • containsAll(Collection c) // boolean // 주어진 Collection 타입 객체가 있는지 확인
  • get(int index) // Generic // 주어진 인덱스에 저장된 객체 리턴
  • isEmpty() // boolean // 컬렉션이 비어 있는지 확인
  • size() // int // 저장돼있는 객체 수 리턴
  • listIterator // ListIterator // 앞 또는 뒤부터 양방향 조회가 가능한 객체 리턴
  1. 객체 삭제
  • clear() // void // 저장된 모든 객체 삭제
  • remove(int index) // Generic // 주어진 인덱스의 객체를 삭제하며, 삭제된 객체 리턴
  • remove(Object o) // boolean // 주어진 객체를 삭제

이렇게 쓰니까 너무 많고 정리하기 힘들다... 다음 거 부터는 중요한 것만 써야겠다...

일단 이 위에서 정리하고 싶은게 뭐가 있나 골라보면, add(E),add(int index, E element), contains(Object o), get(int index), size(), clear(), remove(int index) 정도인 것 같다.
코드로 살펴보자.

list.add(3);//리스트 맨 끝에 3을 추가
list.add(3,99);//첫번째 매개변수 위치에 두번째 매개변수 값을 삽입 ->
    		해당 위치 이후의 데이터는 1칸씩 뒤로 자동으로 밀린다.
list.contains("hi");//hi가 있는지 검색하고 없으면 false값 리턴
list.get(i);//i번째 있는 값을 가져옴
list.size();//list의 크기를 알려줌 {1,2,3}있을 때, 3 리턴
list.clear();//list 안에 있는 객체들 전부 싹 비워줌
list.remove(3); // list의 3번인덱스에 존재하는 값을 삭제

정리해봤다...
다음은 set으로 넘어가보자.

Set

set

  • 저장 순서가 유지되자 않고, 중복 객체도 저장하지 못하는 자료구조다.
  • Null도 중복을 허용하지 않기 때문에 1개의 null만 저장할 수 있다.
  • 구현클래스 HashSet, TreeSet, LinkedSet이 존재한다.
  • 수학으로 비유하자면 집합과 같다.

set은 단순하다고 생각한다. 중복된 값을 받지 못하는데 그 이유가 배열이나 ArrayList처럼 객체를 저장하는 번호나 키의 존재가 없기 때문이다. 그래서 객체를 넣어주면 일정한 알고리즘대로 객체들을 정리한다.

HashSet<Integer> set = new HashSet<Integer>();
		System.out.println("set의 길이 : " + set.size());
		set.add(10);
		System.out.println("set의 길이 : " + set.size());
		System.out.println(set);
		set.add(20);

현재 set의 길이는 2이고, 값은 10, 20이 있는 상태이다. 예전에는 for문을 이용해서 전체 값을 뽑았는데 이 배열은 저장해주는 index값이 없으면 어떻게 출력하나... 하면 foreach문을 사용하면 된다. 이거 굉장히 중요한 것 같다. 크게쓰자

foreach

아직 set 끝난거 아니다. 그리고 이 foreach문 set에서만 쓰는게 아니고 다 쓴다.

for (Integer num : set) {
			System.out.println(num);
		}

이게 for each문이다. 이 코드를 해석하자면, set에서 더이상 빼낼 객체가 없을때까지 계속 객체를 정수형 변수 num에 넣어서 출력하라는 뜻 이다. set에 객체가 없으면 for문이 종료된다. 왜 정수형 변수냐하면 set이 정수형으로 선언되었기 때문이다. 다른 형태로 선언되었으면 다른 형에 넣는다.

다시 set으로
set도 사실 비슷해서 별로 쓸게 없다. 중요한 점만 알아두고 넘어가면 될 것 같다.
set은 절대 중복되는 값을 받지 않는다는 것 이다. 중복되는 값을 받으면, false를 리턴하고, 값을 넣지 않으면서, size도 올라가지 않는다.

System.out.println("set의 길이 : " + set.size());
		set.add(10);
        System.out.println("set의 길이 : " + set.size());
		set.add(10);
        System.out.println("set의 길이 : " + set.size());
		set.add(10);
        System.out.println("set의 길이 : " + set.size());

위와 같은 코드를작성한다고 해도, size는 처음에 10을 넣어줬을때 단 한번 올라가고, foreach문을 통해 set을 출력해보면 '10'값 단 하나만 출력된다.

Map

Map

  • 키(Key)와 값(value)으로 구성되어 있으며 키와 값 모두 객체타입이다.
  • 키는 중복 저장이 불가능하다.(Set의 특성)
  • 값은 중복 저장이 가능하다.(List의 특성)
  • 중복된 키가 들어오는 경우 기존의 키에 해당하는 값에 덮어 쓴다.
  • 구현 클래스는 HashMap, HashTable, LinkedHashMap, Properties,
    TreeMap 이 존재한다.

Map도 다 똑같더라... 다른점이 있다면 키와 값이다. List는 값을 저장해주는 키 값이 0++였다면, Map은 직접 저장이 가능하다.

HashMap<String, String> map = new HashMap<String, String>();
		// put(Key,Value) -> map 데이터를 삽입하는 메소드
		map.put("one", "hi");
		map.put("two", "hello");
		map.put("three", "bye");
		System.out.println(map);
		System.out.println(map.get("one")); //map.get(키값)을 넣어주어서 원하는 값을 뽑아온다.
		System.out.println(map.get("three"));
		System.out.println(map.get("two"));

위와 같은 형식으로 말이다. 키"one"에 저장되어있는 "hi"값이라는 뜻 이다.
map.get("three")를 통해 출력하면 "bye"값이 나온다.
Map도 다 똑같은데 수정이 조금 특이하다.
집어 넣은 형식 그대로 map.put("three", "nono");해주면 수정이다. 이게 값을 덮어써서 다시
map.get("three")를 통해 출력하면 "nono"값이 나온다.

이정도로 오늘의 정리는 끝을 낼 것 같다.
그럼 안녕!!

0개의 댓글