본문 바로가기
공부/Java

자바 제네릭(Generic)이란?

by JERO__ 2022. 3. 18.

제네릭이란?

  • 제네릭(Generic)은 클래스 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법을 의미한다.
class Person<T> {
    public T info;
}

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

→ 앞과 뒤의 모양이 같다!!

  • Person<String> p1 = new Person<String>();
  • Person<StringBuilder> p2 = new Person<StringBuilder>();

제네릭을 왜 쓸까?

  • 사용예시 (기존코드의 중복)
class StudentInfo{
    public int grade;
    public StudentInfo(int grade) {
        this.grade = grade;
    }
}
class StudentPerson{
    public StudentInfo info;
    public StudentPerson(StudentInfo info) {
        this.info = info;
    }
}
class EmployeeInfo{
    public int rank;
    public EmployeeInfo(int rank) {
        this.rank = rank;
    }
}
class EmployeePerson{
    public EmployeeInfo info;
    public EmployeePerson(EmployeeInfo info) {
        this.info = info;
    }
}
public class main {
    public static void main(String[] args) {
        StudentInfo si = new StudentInfo(2);
        StudentPerson sp = new StudentPerson(si);
        System.out.println(sp.info.grade);

        EmployeeInfo ei = new EmployeeInfo(1);
        EmployeePerson ep = new EmployeePerson(ei);
        System.out.println(ep.info.rank);
    }
}
  • 중복 제거(Object) → 잘못 사용되었음에도 오류가 발생하지 않음
class StudentInfo{
    public int grade;
    public StudentInfo(int grade) {
        this.grade = grade;
    }
}
class EmployeeInfo{
    public int rank;
    public EmployeeInfo(int rank) {
        this.rank = rank;
    }
}
class Person{
    public Object info;
    public Person(Object info) {
        this.info = info;
    }
}
public class main {
    public static void main(String[] args) {
        Person p1 = new Person("부장");
        EmployeeInfo ei = (EmployeeInfo) p1.info;
        // EmployeeInfo, Object("부장")
        // 실행 전 오류X. 실행 시 오류 발생!!!!!
    }
}

복수의 제네릭

  • wrapper 클래스 사용하기
class EmployeeInfo {
    public int rank;

    public EmployeeInfo(int rank) {
        this.rank = rank;
    }
}

class Person<T, S>{
    public T info;
    public S id;

    public Person(T info, S id) {
        this.info = info;
        this.id = id;
    }
}

public class main {
    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);
    }
}

제네릭의 생략

class EmployeeInfo {
    public int rank;

    public EmployeeInfo(int rank) {
        this.rank = rank;
    }
}

class Person<T, S>{
    public T info;
    public S id;

    public Person(T info, S id) {
        this.info = info;
        this.id = id;
    }

    public <U> void printInfo(U info){
        System.out.println(info);
    }
}
public class main {
    public static void main(String[] args) {
        EmployeeInfo e = new EmployeeInfo(1);
        Integer i = new Integer(10);
        Person p1 = new Person(e, i);
        
        p1.printInfo(e);
    }
}
  • new Person(e, i)
    • EmployeeInfo, Integer 생략해도 유추해준다.
  • public <U> void printInfo(U info)
    • 클래스 외부에서도 사용 가능

제네릭의 제한(extends)

  • extends를 사용하여 다른 사용을 제한할 수 있다.
abstract class Info{
    public abstract int getLevel1();
}
class EmployeeInfo extends Info{
    public int rank;

    public EmployeeInfo(int rank) {
        this.rank = rank;
    }

    @Override
    public int getLevel1() {
        return this.rank;
    }
}

class Person<T extends Info>{
    public T info;

    public Person(T info) {
        this.info = info;
        // extends Info 했기에 사용가능
        info.getLevel();
    }
}

public class main {
    public static void main(String[] args) {
        Person p1 = new Person(new EmployeeInfo(1)); // 성공
        Person<String> p2 = new Person<String>("부장"); // 실패
    }
}
  • <T extends Info>
    • Info의 자식 클래스만이 참조 가능하다.
    • Info 자리에 interface, class 모두 가능하다.

댓글