java 재네릭
재네릭은 클래스 내부에서 사용할 데이터타입을 외부에서 지정하는 기법을 의미한다.
데이터타입을 외부에서 지정하면 장점뭘까?
메소드 선언에 사용되는 파라미터 형식처럼, 타입 파라미터는 다른 입력값을 같은 코드를 재사용 할 수 있는 방법을 제시한다.
다른점은 형식 파라미터는 값이 아니라 입력이다.
타입파라미터는 타입이 입력!
제네릭 없이 캐스팅이 필요한 코드
List list = new ArrayList(); list.add("hello"); String s = (String) list.get(0);
제네릭을 사용하여 코드 작성시,캐스팅이 필요 없어진다.
List<String> list = new ArrayList<String>(); list.add("hello"); String s = list.get(0); // no cast
제네릭을 사용함으로써 일반적인 알고리즘을 구현하도록 지원한다.
generics를 사용하면서 다양한 타입들의 콜렉션을 사용할 수 있고 더 안정적이고 읽기 쉬운 코드를 일반적인 알고리즘으로 구현할 수 있다.
좀더 자세히 알아보자.
아래의 코드를 살펴보자.
class Person<T>{ public T info; } public class GenericDemo{ public static void main(String[] arge){ Person<String> p1 = new Person<String>(); Person<StringBuilder> p2 = new Person<StringBuilder>(); } }
데이터 타입 결과는
p1.info = String
p2.info = StringBuilder
각각의 인스턴스를 생성할 때 사용한 <> 사이에 어떤 데이터 타입을 사용했느냐에 달려있다.
클래스 선언부
public
T info;
클래스 필드 info의 데이터 타입은 T로 되어있다. 실제로 T라는 데티어 타입은 존재하지 않는다.
이값은 아래 코드의 T에서 정해진다.
제너릭 클래스 선언부
class
Person<T>{
제네릭 클래스의 인스턴스 생성부
Person<String> p1 =
new
Person<String>();
제네릭 클래스의 인스턴스 생성시 <String> 으로 지정하면서 제네릭 T info는 String info 가 된다.
재네릭 사용하는 이유
class StudentInfo{ public int grade; StudentInfo(int grade){ this.grade = grade; } } class StudentPerson{ public StudentInfo info; StudentPerson(StudentInfo info){ this.info = info; } } class EmployeeInfo{ public int rank; EmployeeInfo(int rank){ this.rank = rank; } } class EmployeePerson{ public EmployeeInfo info; EmployeePerson(EmployeeInfo info){ this.info = info; } } public class GenericDemo { public static void main(String[] args) { StudentInfo si = new StudentInfo(2); StudentPerson sp = new StudentPerson(si); System.out.println(sp.info.grade); // 2 EmployeeInfo ei = new EmployeeInfo(1); EmployeePerson ep = new EmployeePerson(ei); System.out.println(ep.info.rank); // 1 } }
위 코드를 보면 StudentPerson와 EmployeePerson가 중복되는 클래스이다.
f(x) = x 함수 클래스로 x 매개변수를 제네릭 클래스로 구현하여 StudentPerson와 EmployeePerson 클래스중복을 제거해보자.
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); // 컴파일 실패 } }
기본 데이터 타입과 제네릭
제네릭은 참조 데이터 타입에 대해서만 사용할 수 있다. 기본 데이터 타입에서는 사용할 수 없다. 따라서 아래 코드의 int는 오류난다.
int . char, double ..등등 은 기본데이터로 사용할 수 없다. int 대신 integer 로 대신하여 사용할 수 있다.
class EmployeeInfo{ public int rank; EmployeeInfo(int rank){ this.rank = rank; } } class Person<T, S>{ public T info; public S id; Person(T info, S id){ this.info = info; this.id = id; } } public class GenericDemo { public static void main(String[] args) { Person<EmployeeInfo, int> p1 = new Person<EmployeeInfo, int>(new EmployeeInfo(1), 1); } }
복수 제네릭
클래스 내에서 여러개의 제네릭을 필요로 하는 경우 아래의 코드를 참조하자.
class EmployeeInfo{ public int rank; EmployeeInfo(int rank){ this.rank = rank; } } class Person<T, S>{ public T info; public S id; Person(T info, S id){ this.info = info; this.id = id; } } 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); System.out.println(p1.id.intValue()); } }
재네릭 메소드 사용
class EmployeeInfo{ public int rank; EmployeeInfo(int rank){ this.rank = rank; } } class Person<T, S>{ public T info; public S id; Person(T info, S id){ this.info = info; this.id = id; } 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); } }
Person p2 =
new
Person(e, i);
extends 로 재네릭으로 올 수 있는 데이터 타입을 특정 클래스의 자식으로 제한할 수 있다.
extends는 상속 관계인 클래스 뿐만 아니라 구현(implements)의 관계에서도 사용할 수 있다.
interface Info{ int getLevel(); } class EmployeeInfo implements Info{ public int rank; EmployeeInfo(int rank){ this.rank = rank; } public int getLevel(){ return this.rank; } } class Person<T extends Info>{ public T info; Person(T info){ this.info = info; } } public class GenericDemo { public static void main(String[] args) { Person p1 = new Person(new EmployeeInfo(1)); Person<String> p2 = new Person<String>("부장"); } }
제네릭에 대해 기본적인 개념만 살펴보았다.
'JAVA > JAVA' 카테고리의 다른 글
[객체지향] JAVA SOLID 원칙 (0) | 2019.02.23 |
---|---|
제네릭 메소드 (0) | 2017.05.17 |
다형성 (0) | 2015.08.28 |
클라이언트 ip 구하기 (0) | 2015.08.13 |
java foreach 반복문 (0) | 2015.08.13 |