본문 바로가기
Java & JSP

Java Generic & Collection Framework(제네릭&콜렉션 프레임워크)

by 작심평생 2019. 5. 22.
드.디.어 에버노트에 정리했던 내용을 불러왔습니다...
왜 새로운 글쓰기는 못 가져오는 건지..세상 불-편

해당 내용은 생활코딩(언제나 강의 잘 보고있습니다.. 정말 감사합니다!)님 강의자료를 보고 작성했습니다!
관심있으신 분은 생활코딩님 유튜브나 해당 링크에서 강의들으시면 좋을 것 같습니다!!
문제 시 삭제 혹은 비공개 처리하겠습니다..

이번에는 제네릭과 콜렉션 프레임워크 기초라서 나중에 콜렉션의 상세 Class 관련 공부를 할 계획!! 예를 들어 각 클래스의 장단점 (속도가 빠르다, 어떤 경우 좋다 등) 
==> 까먹지 말고 공부하자!!


++ 혹시 정리한 내용 중에 
'어? 저건 저렇게 이해하는게 아닌데..?' 같은 부분이 있다면
정정 댓글 부탁드립니다! 
많이 부족하고 배워나가는 단계입니다 헤헤..



제네릭(Generic)
:래스 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법.. 인스턴스 만들 때 지정하게됨. (new ~~<string>(); 이런식) 
: <>에 넣는 부분..
: <> 에는 참조형 데이터 타입만 올 수 있음 => 기본 데이터 타입은 못옴 (int, char ...)  왜? 기본 데이터 타입은 객체가 아니기 때문에
                                                              그러면 아예 못 사용하나? NO! 객체인 것처럼 만들 수 있음 => 래퍼(wrapper)클래스[ 기본 데이터 타입을 객체로 포장하는 객체 ]
                                                              ex) int의 wrapper class = Integer, double은 Double ...등등


사용이유!
  • 컴파일 단계에서 오류가 검출된다. ==> 런타임에서 에러가 발생하면 오류 발생 시 찾기 힘듦 따라서 컴파일 단계에서 에러를 검출하는 게 중요!!
  • 중복의 제거와 타입 안전성을 동시에 추구할 수 있게 되었다.

제네릭화 한 예시코드
package org.opentutorials.javatutorials.generic;
class StudentInfo{
public int grade;
StudentInfo(int grade){ this.grade = grade; }
}
class EmployeeInfo{
public int rank;
EmployeeInfo(int rank){ this.rank = rank; }
}
class Person<T>{
public T info;
Person(T info){ this.info = info; }
}
public class GenericDemo {
public static void main(String[] args) {
Person<EmployeeInfo> p1 = new Person<EmployeeInfo>(new EmployeeInfo(1));
EmployeeInfo ei1 = p1.info;
System.out.println(ei1.rank); // 성공
Person<String> p2 = new Person<String>("부장");
String ei2 = p2.info;
System.out.println(ei2.rank); // 컴파일 실패
}
}

복수의 제네릭
: class Person<T, S> {} 이렇게 , 찍어서 사용하면 됨.

<wrapper class(래퍼클래스)를 통한 원시 데이터 우회에서 사용하기>
: 여기선 int..



제네릭의 생략

EmployeeInfo e = new EmployeeInfo(1);
Integer i = new Integer(10);
Person<EmployeeInfo, Integer> p1 = new Person<EmployeeInfo, Integer>(e, i);
Person p2 = new Person(e, i);

    =>   e와 i의 데이터 타입을 알고 있기 때문에 명시적을 써주지 않아도 작동한다. (개인적으론 써주는게 덜 헷갈릴꺼같음)

메소드에서도 사용할 수 있음. 

public <U> void printInfo(U info){
System.out.println(info);
}

public class GenericDemo {
public static void main(String[] args) {
EmployeeInfo e = new EmployeeInfo(1);
Integer i = new Integer(10);
Person<EmployeeInfo, Integer> p1 = new Person<EmployeeInfo, Integer>(e, i);
p1.<EmployeeInfo>printInfo(e);
p1.printInfo(e); // 둘 다 같은 것임.
}
}


제네릭의 제한 ( extends [ 제네릭으로 올 수 있는 데이터 타입을 특정 클래스의 자식으로 제한할 수 있다. ] )
: object나 제네릭이나 아무거나 올 수 있는거 아님? => 제네릭은 제한을 걸 수 있음
class Person<T extends Info>{}
: <>안에서의 extends"T의 부모가 Info다" 라는 것이고 사용 시 자바는 이에 해당하는지 확인함. 이는 class, interface인 경우에도 동일 
   => interface라고 <>안의 extends가 implements로 바꿔야 하는 게 아님.


++ Super라는 것도 있음. extends와 다르게 부모를 제한하는 것 ( 필요 시 찾아보자)

만약 제한을 안걸면 <T extends Object>와 같은 말이됨. 이는 만약에 Info안에 a(); 라는 메소드가 있을 때 이를 호출할 수 없다는 뜻임.
=> Object의 기본 메소드 (toString 같은 것만 되고)만 호출할 수 있음.




Collections Framework(컬렉션즈 프레임워크 = 컨테이너)
다양한 상황에서 사용할 수 있는 다양한 컨테이너를 제공하는데 이것을 컬렉션즈 프래임워크라고 함

ArrayList(어레이리스트) : 크기를 미리 지정하지 않기 때문에 얼마든지 많은 수의 값을 저장할 수 있음.                    

    => 배열(=Array)의 불편함(한번 정해진 배열의 크기를 변경할 수 없다는 점)을 줄이기위해


.add(); : ArrayList에 데이터 추가 (기본적으로 Object 형식으로 추가됨 -> 즉, (String) 이렇게 cast(캐스트;형변환)해야함 -> 하지만 제네릭써서 타입 제한하면 해결)

                         ex).  ArrayList<String> al = new ArrayList<String>();

.get(); : ArrayList에 있는 데이터 꺼냄

.size(); : ArrayList에 담긴 데이터의 개수

HashSet(해시셋) - 역시 제네릭 이용하여 타입 제한함

.add() : 데이터 추가 

.containsAll(인자) :  A.containsAll(B);라고 하면 A라는 집합(set)에 B라는 집합의 전체 값이 들어있는지. True/False로 반환. 부분집합;subset 여부
                                                        


.addAll(인자) : A.addAll(B);라고 하면 A의 set에 B를 전부 추가한다. = Union;합집합

                                             


.retainAll(인자) : A.retainAll(B);라고 하면 A에도 있고 B에도 있는 값들만 A에 담겠다. 

    실행하면 A의 값은 해당하는 값만 남게됨. = Intersect;교집합

                                                  

  
.removeAll(인자) : A.removeAll(B); 라고하면 A에만 있는 값만 남긴다. = Difference;차집합
                                                    


----> 자세한건 아래 그림을 참고. 미묘하게 메소드가 다름. 무조건 HashSet만 쓸 수 있는 메소드가 아닌 듯 하다.
        + Set 이던 List 이던, 잘 모르면 Collection 인터페이스에 정의된 메소드를 사용하는 게 좋음 => 나중에 필요에 의해 바꿀 수 있기 때문.
물론 받아줄 때는 "Collection<> asd = ~~~" 이런 식으로 받아줘야겠지
            만약, List에 정의된 메소드를 이용했다 => 그럼 이후에도 List에 정의된 메소드를 쓰면 ArrayList, LinkedList ...등 소스코드를 최소한 변경으로 적용할 수 있음.
            즉, List / Set에 정의된 메소드를 사용하면 나중에 세부적으로 들어갈 때 최소한으로 소스코드 변경할 수 있음.

        + 아래 그림에서 Set의 인터페이스는 비어있는데 이는 Collection 인터페이스에 정의된 메소드를 그대로 이용한다는 것(그대로 상속받은 것임)


List와 Set의 차이
List 중복을 허용하고 저장되는 순서가 유지됨(순차적으로 중복여부 상관없이 저장하기 때문)
  Set 중복을 허용하지 않고 순서가 없음(=> 중복되는 값은 무시되기 때문에 순서가 없음)

Set = '집합' 이란 뜻 = 교집합, 차집합 등의 연산을 가능

하늘색(ex. Collection) : 인터페이스
진한파랑(ex. AbstractList) : 클래스



Iterator (참고: https://youtu.be/DQN32cBaUEE)
인터페이스 Collection에 정의되어 있음. 즉,  Collection을 구현하고 있는 모든 컬렉션즈 프레임웍크는 이 메소드를 구현가능. (ArrayList도 해당 방법 사용가능하다는 것!)
   메소드 iterator(.iterator)의 호출 결과는 인터페이스 Iterator를 구현한 객체를 리턴

  • .hasNext() : 반복할 데이터가 더 있으면 true, 더 이상 반복할 데이터가 없다면 false를 리턴한다.
  • .next() : hasNext가 true라는 것은 next가 리턴할 데이터가 존재한다는 의미다. 

Iterator ai = al.iterator();
while(ai.hasNext()){
System.out.println(ai.next());
}

: Iterator를 이용하면 가상의 객체?암튼 그런게 생김(위의 코드에선 ai라는 Iterator에 al의 값을 그대로 가지고 있다고 생각) 그럼 while문을 돌면서
 다음 값이 있으면 계속 돌고 next()를 통해 값을 리턴해줌. 그러면 리턴된 값은 없어지게됨. 만약 1,2,3 이있다면 1이 출력되면 2,3만 남는다는 소리다.
 이 때 주의할 점은 원본 데이터, al에 들어있는 값이 사라지는 게 아니라는 것. 

그리고 Map.Entry를 set으로 받아 iterator를 이용하는 것 보니, iterator는 순서성을 가진 듯 하다. (아래 내용)



Map(맵)
: Key - Value로 이뤄짐(파이썬의 딕셔너리와 같은 개념이라 생각하자)
: Key값은 중복 불가(그래도 중복된 key&value를 쓰면 key & value는 덮어씌어짐) => 총 2개가 생기는게 아니라 1개의 Key & Value. 중복이 안 된다는 것
: Iterator가 없어서 entrySet();을 이용. (foreach문 이용도 마찬가지)

.put(키값, 벨류값) : a.put("one",1); 면 Key 값은 one이고 Value는 1이다라고 추가하는 것.

.get(키값) : a.get("one"); 면 Key값이 one인 Value를 리턴

.entrySet(); : Set 데이터 타입의 객체 리턴. 


Map.Entry<A,B>라는 인터페이스를 이용. 여기서 A는 getKey()의 데이터 타입, B는 getValue()의 데이터 타입 => 기존 map에서 정의한 타입과 맞춰줘야하는 듯.
.getKey() : 키값 리턴

.getValue() : Value값 리턴

                                    


++ Map이나 Collection이나 공통
     : 해당 컬렉션을 대표하는 인터페이스를 사용하는 것이 좋다
       ex)  Map<String, Integer> a = new HashMap<String, Integer>();


Collection Framework에서의 정렬
: Collections 클래스의 메소드 이용 (여기안에 있는 메소드는 static이라 바로 호출 가능. Collections.sort이런식)

sort를 메소드를 확인해보면 List형식만 정렬 가능하게 되어있음. + Comparable 라는 인터페이스를 implements 하고 있어야함. => class ~ implements Comparable{}이런식
Comparable 인터페이스는 compareTo라는 메소드를 구현하도록 강제하고 있음. 

public int compareTo(Object o) {
return this.serial - ((Computer)o).serial;
}

sort()의 경우 비교해서 크면 양수, 같으면 0, 작으면 음수를 리턴함.

---> 알고리즘이나 자료구조랑 같이 공부하는 걸 추천

++ 어떤 메소드나 계층구조 등을 확인하는 습관을 가지자. API 확인도!





1. List, Set, Queue(언급이 없었지만)Map 자료구조에 속한 Class들의 장단점, 사용하면 좋을 때 등 찾아서 공부하기

2. Generic 제한 시 Super 관련 찾아보기

3. 해당 메소드 계층구조, API 등 상세 내용도 꼼꼼히 확인할 것

4. 자료구조 관련 이론 쌓고 알고리즘 공부하기


'Java & JSP' 카테고리의 다른 글

IE 9에서 input태그 file 에러 이슈, input태그 accecpt, multiple 지원 버전  (0) 2020.03.10
EL & JSTL  (0) 2019.06.02
@SuppressWarnings..?  (0) 2019.05.26

댓글