1. 제네릭(Generic)
만약 어느 기사의 댓글이 저장되어있는 DB에서 10건을 가져와서 자바를 통해 프론트단에 출력시키려한다.
그럴 떄 댓글 1개씩 가져와서 프론트단에 출력을 시키는 것이 아니라 10건씩 동시에 가져와서 출력을 시키면 작업이 더 가볍고 편할 것이다.
이럴 때 사용하는 것이 바로 제네릭이다.
제네릭은 데이터들의 형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있도록 하는 방법을 말한다.
위에서 말했듯 우리가 댓글을 가져올 것인데 이 안에는 String에 대한 클래스, Integer에 대한 클래스 등의 클래스의 자료형을 여러가지로 가져오고 싶다.
이 때 클래스 내부에서 지정하는 것이 아니라 외부에서 사용자에 의해 지정되는 것을 제네릭이라 말한다.
제네릭은 문자 그대로 '일반적이다'라는 뜻을 갖고 있다. 특정(Specific) 타입을 미리 지정해주는 것이 아닌 필요에 의해 지정할 수 있는 타입을 갖고 있는 일반(Generic) 타입이란 뜻이다.
- Generic의 장점
1) 제네릭을 사용하면 잘못된 타입이 들어올 수 있는 것을 컴파일 단계에서 방지할 수 있다.
2) 클래스 외부에서 타입을 지정해주기 때문에 따로 타입을 체크하고 변환해줄 필요가 없다. 즉, 관리하기가 편하다.
3) 비슷한 기능을 지원하는 경우 코드의 재사용성이 높아진다.
2. Java Collection Framwork
이런 제네릭을 사용할 땐 자바 안에 만들어져있는 컬렉션 프레임워크를 사용하게 된다.
위에서 말했듯 자바는 자료형이 고정적인 배열의 문제점을 해결하기 위해 널리 알려져있는 자료구조를 바탕으로 라이브러리를 만들어두었다. 이것을 컬렉션 프레임워크라 부른다.
컬렉션 프레임 워크는 크게 세 종류로 나누어진다(Stack이나 Queue도 있지만 여기서는 다루지 않으려 한다).
아래의 <E>는 제네릭의 사용 방법 중 하나인데 이번 게시글에선 제네릭보단 컬렉션 프레임워크에 초점을 맞추려고 하기에 여기서만 기술하고 코드에서는 따로 사용하진 않으려한다.
1) List<E> : 순서(Index)가 있다. 인덱스는 0부터 시작
종류 - Vector, ArrayList ~~~
2) Set<E> : 순서가 없다
종류 - HashSet ~~~
3) Map <E> : 순서가 없다.
Key와 Value의 쌍으로 구성되어 있다.
Key는 중복을 허용하지만 Value는 중복을 허용하지 않는다.
종류 - HashMap, Properties, HashTable ~~~
구현을 할 때는 다형성을 이용하여 아래와 같이 구현을 한다.
// 클래스들간의 관계 구조 확인
interface List {}
class Vector implements List{}
class ArrayList implements List{}
interface Set{}
class HashSet implements Set{}
interface Map{}
class HassMap implements Map{}
class Properties implements Map{}
// 다형성
List list = new Vector()
List list = new ArrayList()
Set set = new HashSet()
Map map = new HashMap()
여기까지 적어도 사실 잘 감이 안온다.
일반적인 배열과 컬렉션 프레임워크로 구현한 제네릭을 비교해가면서 확인해보자.
3. 배열과 컬렉션 프레임워크 비교하기
1) 일반 배열
// 배열 : 자료를 모아놓을 수 있다
int[] num = new int[100];
System.out.println(num.length); // 요소의 갯수 100
위와 같이 num이라는 이름의 100개의 요소가 들어갈 수 있는 배열을 만들었다.
num 배열의 길이를 출력시키니 100이 나온다.
하지만 이 배열 안에는 int 자료형을 가진 값들만 들어올 수 있다.
다음으론 컬렉션 프레임워크를 사용하여 값들의 집합을 만들어보자.
2) 컬렉션 프레임워크 - List 계열
// 1. List 계열
// <E> Element 요소
Vector vec = new Vector();
vec.add(3);
vec.add(2.4);
vec.add('R');
vec.add("KOREA");
vec.add(new Integer(5));
vec.add(new Double(6.7));
// Integer inte = new Integer(5) Old Version
// Integer inte = 5 New Version
System.out.println(vec.size()); // 요소의 갯수 6
// 다형성
List list = new ArrayList();
list.add(5);
list.add(6.7);
list.add('M');
list.add("SEOUL");
System.out.println(list.size()); // 요소의 갯수 4
컬렉션 프레임워크인 Vector를 활용하여 vec이라는 이름의 집합을 만들었다.
(Vector가 너무 많은 메모리 공간을 차지해서 작은 작업이라면 ArrayList를 더 선호한다)
이 안에는 int형도, double형도, char형도, String형도 들어가있다.
잘 들어가있는지 확인하기 위해 아래의 코드를 작성하고 출력시켜보았다.
for(int i=0; i<vec.size(); i++) {
System.out.println(vec.get(i));
}
위와 같이 서로 다른 자료형들이 한곳에 잘 들어가있는 모습을 확인할 수 있다.
이처럼 한 가지의 자료형태를 가진 값들만 모을 수 있는 배열의 단점을 보완한 것이 바로 컬렉션 프레임워크를 활용한 제네릭이다.
* List 컬렉션 프레임워크와 함께 사용할 수 있는 메서드들도 몇 가지 알아봐보자. *
메서드 이름 | 기능 | 예시 |
.add(i) | 요소에 i값을 저장한다 | vec.add(21) |
.size() | 요소의 개수를 알려준다 | vec.size() |
.get(i) | i번째 요소를 불러온다 | vec.get(i) |
.remove(i) | i번쨰 요소를 제거한다 | vec.remove(i) |
.removeAllElements() | 갖고 있는 요소를 전부 제거한다 | vet.removeAllElements |
.isEmpty() | 요소의 개수가 0개인지 확인한다 | vec.isEmty() |
3) 컬렉션 프레임워크 - Set 계열
Set set = new HashSet();
set.add(3);
set.add(2.4);
set.add('R');
set.add("BUSAN");
set.add(new Integer(7));
System.out.println(set.size());
Set은 List처럼 똑같이 여러 형태의 데이터를 저장하지만 차이점이 있다면 순서가 없고 중복을 허용하지 않는다는 것이다.
순서가 없기 때문에 Set 안에 들어있는 자료들에 접근하는 것은 List에서 접근하는 방법과는 다른 방법으로 접근해야한다.
만약 내가 3이라는 데이터를 출력시키고 싶다.
저 3이 0번째처럼 보이지만 Set으로 이 데이터들을 모아놓았기 때문에 사실 아무런 순서가 없다는 것을 기억해야한다.
그래서 cursor 라는 개념이 등장한다.
어떠한 요소를 가리킨다는 의미이며 가리킬 요소가 있으면 true, 없으면 false 값을 반환한다.
cursor의 특징은 순서는 없지만 다음 것을 불러오라고는 할 수 있다.
(이전 것을 불러오라고 할 수도 있다)
이러한 커서의 특징으로 반복문을 사용하여 출력시키면 Set으로 저장된 자료들에 접근할 수 있는 것이다.
이 때 사용되는 명령어가 Iterator(반복자)이다.
Iterator iter = set.iterator();
while(iter.hasNext()) { // 다음 cursor가 있는지
// cursor가 가리키는 요소 가져오기
Object obj=iter.next();
System.out.println(obj);
} // while end
언제 Set을 사용할까?
Set은 요소들이 중복이 되지 않으며, 특히 HashSet의 경우에는 요소들의 주소값에 접근을 한다.
그렇기 때문에 List와는 비교도 안되는 속도로 요소를 검색하고 찾을 수 있다.
* Set 컬렉션 프레임워크와 함께 사용할 수 있는 메서드들도 몇 가지 알아봐보자. *
메서드 이름 | 기능 | 예시 |
.add(i) | 요소에 i값을 저장한다 | set.add(21) |
.size() | 요소의 개수를 알려준다 | set.size() |
.iterator() | 저장된 요소에 커서를 생성해준다. | set.iterator() |
<iterator를 만들고 난 뒤> *.next() |
만들어진 커서 *의 다음 값을 가져온다 | iter.next() |
.remove() | next()로 읽어온 요소를 삭제한다. | set.remove() |
.removeAll(set) | 갖고 있는 요소를 전부 제거한다 | set.removeAll(set) |
.isEmpty() | 요소의 개수가 0개인지 확인한다 | set.isEmty() |
4) 컬렉션 프레임워크 - Map 계열
Map은 Set처럼 순서가 없이 값들을 저장하지만 각각의 값마다 이름이 붙는다.
그래서 이름은 Key 값으로, 값은 Value 값으로 짝을 지어 저장을 해둔다.
이와 같은 형태로 데이터를 저장하는 것은 JSON, 파이선(딕셔너리), NoSQL 등에서도 확인할 수 있다.
- HashMap
HashMap map = new HashMap();
map.put("one", 3);
map.put("two", 2.4);
map.put("three", 'R');
map.put("four", "손흥민");
System.out.println(map.size()); // 4
System.out.println(map.get("four")); // "손흥민"
- Properties : Key와 Value 모두 String으로 저장할 때 사용하는 특화된 클래스이다.
// Properties 클래스
Properties db = new Properties();
db.put("url", "http://localhost:1521");
db.put("username", "itwill");
db.put("password", "12341234");
System.out.println(db.get("url"));
System.out.println(db.get("username"));
System.out.println(db.get("password"));
* Map 컬렉션 프레임워크와 함께 사용할 수 있는 메서드들도 몇 가지 알아봐보자. *
메서드 이름 | 기능 | 예시 |
.put(K, V) | Key값 K에 Value값 V를 저장한다 | map.put("one", 21) |
.size() | 요소의 개수를 알려준다 | map.size() |
.get(Key) | Key값이 갖고 있는 Value를 불러온다 | map.get(Key) |
.remove(Key) | Key값에 해당되는 Value를 삭제한다 | map.remove(Key) |
여기까지 컬렉션 프레임워크의 개념과 사용방법을 알아보았다.
다음 게시글은 제네릭의 사용방법을 더 구체적으로 알아보려한다.
'⁂ Java > : 기본 익히기' 카테고리의 다른 글
[JAVA] #9-5 스레드(Thread) (0) | 2022.09.19 |
---|---|
[JAVA] #9-4 제네릭(Generic) 이해하기 2 - 제네릭 (0) | 2022.09.16 |
[JAVA] #9-2 예외처리(Exception) 2 - throws (0) | 2022.09.16 |
[JAVA] #9-1 예외처리(Exception) 1 - try...catch...finally (0) | 2022.09.16 |
[JAVA] #8-6 이너 클래스(Inner Class) (0) | 2022.09.15 |