본문 바로가기

Programming/자바

생활코딩 자바 - 제네릭

제네릭의 사용

제네릭 : 클래스 내부에서 사용할 데이터타입을 외부에서 지정

 

메소드의 매개변수와 유사하게 작동

 

  •  

 

내부

class Person<T>{    
public T info;   
}

 

외부
public class GenericDemo {
public static void main(String[] args) {
Person<String> p1 = new Person<String>();     //info=> String
Person<StringBuilder> p2 = new Person<StringBuilder>();    //info=> StringBuilder
}}

 

=> 클래스를 정의 할 때 info의 데이터 타입을 확정하지 않고, 인스턴스를 생성할 때 데이터 타입을 지정

 

 

 

제네릭 사용 이유

 

  •  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class StudentI{
    public int grade;
    StudentI(int grade){
        this.grade=grade;
    }
}
 
 
class EmployeeI{
    public int rank;
    EmployeeI(int rank){
        this.rank=rank;
    }
}
 
class People{
    public Object info;
    People(Object info){this.info=info;}
}
 
 
public class GenericDemo3 {
    public static void main(String[] args) {
        People p1 = new People("부장");1
    }
 
}
cs

=> 원래대로라면 메인메소드에서 EmployeeI나 StudentI의 인스턴스가 괄호 안에 들어와야 하나, 

   코드에서처럼 문자열 "부장"이 들어가도 에러 표시가 뜨지 않음 (Object가 허용한 것) => 심각한 문제

 

 

 

1
2
3
4
5
6
7
public class GenericDemo3 {
    public static void main(String[] args) {
        People p1 = new People("부장");
        EmployeeI ei = (EmployeeI) p1.info;
//p1의 info는 Object라는 일반적인(=큰?) 데이터타입 가짐 -> EmployeeI로 형변환 필
    }
 
}
cs

//

Exception in thread "main" java.lang.ClassCastException: class java.lang.String cannot be cast to class org.opentutorials.javatutorials.generic.EmployeeI (java.lang.String is in module java.base of loader 'bootstrap'; org.opentutorials.javatutorials.generic.EmployeeI is in unnamed module of loader 'app')

 

=> 작성 시 에러 뜨지 않지만 출력 시 에러 (컴파일 에러 X, 런타임 에러 O)

=> 타입이 안전하지 않음 (Type Safety)

 

 

∴ 제네릭 => 타입의 안정성 + 코드 중복 제거 위해 생성

 

 

 

 

제네릭의 특징 1 - 복수의 제네릭

 

  •  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class EmployeeI{
    public int rank;
    EmployeeI(int rank){
        this.rank=rank;
    }
}
 
class P <T, S>{ //쉼표 사용, 다른 이름
    public T info;
    public S id;
    P(T info, S id){
        this.info = info;
        this.id = id;
    }
}
 
public class GenericDemo3 {
    public static void main(String[] args) {
    P<EmployeeI, int> p1 = new P<EmployeeI, int> (new EmployeeI(1), 1);
   } //에러 발생
 
}
cs

 

  • int 에러 해결
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class EmployeeI{
    public int rank;
    EmployeeI(int rank){
        this.rank=rank;
    }
}
 
class P <T, S>{    //T, S에는 참조형 데이터타입만 올 수 있음 (int, char 등 기본 X)
    public T info;
    public S id;
    P(T info, S id){
        this.info = info;
        this.id = id;
    }
}
 
public class GenericDemo3 {
    public static void main(String[] args) {
        P<EmployeeI, Integer> p1 = new P<EmployeeI, Integer> (new EmployeeI(1), 1);
        //래퍼(Wrapper) 클래스 사용 => 기본 데이터타입을 객체로 포장
        System.out.println(p1.id);
    }
 
}
 
cs

 

 

 

제네릭의 특징 2 - 제네릭의 생략

 

  •  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class EmployeeI{
    public int rank;
    EmployeeI(int rank){this.rank=rank;}
}
 
class P <T, S>{
    public T info;
    public S id;
    P(T info, S id){
        this.info = info;
        this.id = id;
    }
    public <U> void printInfo(U info) {
        System.out.println(info);
    }
}
 
public class GenericDemo3 {
    public static void main(String[] args) {
        EmployeeI e = new EmployeeI(1);
        Integer i = new Integer(10);
        P p1 = new P(e,i); //윗줄에서 정의해서 데이터타입 생략 가능    
    }
 
}
cs

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class EmployeeI{
    public int rank;
    EmployeeI(int rank){this.rank=rank;}
}
 
class P <T, S>{
    public T info;
    public S id;
    P(T info, S id){
        this.info = info;
        this.id = id;
    }
    public <U> void printInfo(U info) {    
//printInfo 메소드 안에서 U로 지정된 데이터타입=> info 매개변수의 제너릭 데이터타입이 됨
        System.out.println(info);
    }
}
 
public class GenericDemo3 {
    public static void main(String[] args) {
        EmployeeI e = new EmployeeI(1);
        Integer i = new Integer(10);
        P p1 = new P(e,i);    
       p1.printInfo(e); //여기서도 데이터타입 생략 가능
    }
 
}
cs

 

 

 

 

 

제네릭의 제한

 

  •  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
abstract class Info{
    public abstract int getLevel();
}
 
class EI extends Info{
    public int rank;
    EI(int rank){this.rank=rank;}
    public int getLevel() {
        return this.rank;
    }
}
 
class Per <extends Info>{   //Info나 그 하위클래스만 들어오도록 제한
    public T info;
    Per(T info){
        this.info = info;
    }}
 
public class GenericDemo3 {
    public static void main(String[] args) {
        Per<EI> p1 = new Per<EI>(new EI(1));    
        Per<String> p2 = new Per<String>("부장");    //Info와 관련없기 때문에 컴파일 에러
    }
 
}
cs

 

  • 클래스->인터페이스도 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
interface Info{
    int getLevel();
}
 
class EI implements Info{
    public int rank;
    EI(int rank){this.rank=rank;}
    public int getLevel() {
        return this.rank;
    }
}
 
class Per <extends Info>{
    public T info;
    Per(T info){
        this.info = info;
    }}
 
public class GenericDemo3 {
    public static void main(String[] args) {
        Per<EI> p1 = new Per<EI>(new EI(1));    
    }
 
}
cs

 

 

  • 제한 없앨 때 발생하는 오류
1
2
3
4
5
6
7
8
class Per <T>{    // <T>=<T extends Object>
    public T info;
    Per(T info){
        this.info = info;
        info.getLevel();    //getLevel은 Object에는 없고 Info에 있으므로 에러
    }}
 
 
cs

 

 

 

 

 

 

 

 

 

'Programming > 자바' 카테고리의 다른 글

자바 재정리 - 참조  (0) 2022.08.05
생활코딩 자바 - Collections framework  (0) 2022.04.24
생활코딩 자바 - 참조 ?  (0) 2022.04.19
생활코딩 자바 - 상수2 - enum  (0) 2022.04.18
생활코딩 자바 - Object 클래스  (0) 2022.04.18