JDK 1.5 이전에서는 여러 타입을 사용하는 대부분의 클래스나 메소드에서 인수나 반환값으로 Object 타입을 사용했다.
이 경우에는 반환된 Object 객체를 다시 원하는 타입으로 타입 변환해야 한다.
그리고 원하지 않는 자료형이 입력되었을 때의 오류를 컴파일 시점에서 잡아낼 수 없다.
(Object 클래스는 모든 클래스의 조상(부모)이므로 모든 타입이 들어갈 수 있다.)
자바에서 제네릭(Generic)이란 데이터의 타입(Data Type)을 일반화한다(Generalize)는 것을 의미한다.
제네릭은 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하는 방법이다.
이렇게 컴파일 시에 미리 타입 검사(Type Check)를 수행하면 다음과 같은 장점을 가진다.
1. 프로그램 성능저하를 유발하는 캐스팅(강제 데이터타입 변환)을 제거한다.
- 매번 데이터 타입을 강제로 캐스팅하면, 프로그램 성능 저하가 발생한다.
2. 코드절약 및 코드 재사용성을 증진시켜 유지보수를 편하게 한다.
- Generic 이 없다면, 매번 필요한 데이터 타입에 맞는 새로운 클래스 또는 메소드를 작성해야 한다.
3. 컴파일시 타입오류를 체크하여, 사전에 엄격한 데이터타입 체크를 가능케한다.
예제 1
package ex_Generic; //Object 타입을 사용하면 모든 종류의 자바 객체를 저장할 수 있다는 장점은 있지만 //저장할 때 타입 변환이 발생하고, 읽어올 때도 타입 변환이 발생한다. //이러한 캐스팅이 빈번해지면 전체 프로그램 성능에 좋지 못한 결과가 발생할 수 있다. // 제네릭은 클래스를 설계할 때 구체적인 타입을 명시하지 않고, // 타입 파라미터로 대체했다가, 실제 클래스가 사용될 때 구체적인 타입을 지정함으로써 타입 변환을 최소화한다. public class Box<T> { // T라는 이름이 매개변수화된 자료형임을 나타냄. private T item; // T에 해당하는 자료형의 이름은 인스턴스를 생성하는 순간에 결정된다. // T는 상징적인 문자 public Box() { // 생성자 } public Box(T item) { // 매개변수가 있는 생성자 this.item = item; } public void setData(T item) { // T[] arr this.item = item; } public T getData() { return item; } }
|
package ex_Generic;
import java.util.ArrayList; import java.util.List;
abstract class Animal { public void go() { System.out.println("Animal"); } } class Dog extends Animal { public void go() { System.out.println("Dog"); } } class Cat extends Animal { public void go() { System.out.println("Cat"); } }
public class Main { @SuppressWarnings("unchecked") public static <T extends Animal> void doAction(List<T> animals) { animals.add((T) new Cat()); for (Animal animal: animals) { animal.go(); } } public static void main(String[] args) { // 한정된 타입을 사용하도록 유도함으로써 타입 안전성 보장 // 인스턴스 생성시 자료형을 지정한다. Integer Box<Integer> box1 = new Box<>(); box1.setData(10); System.out.println(box1.getData()); // 인스턴스 생성시 자료형을 지정한다. String Box<String> box2 = new Box<>(); box2.setData("오랜지"); System.out.println(box2.getData()); // 컬렉션 프레임워크(Collections Framework) // Collection : 객체를 수집해서 저장하는 역할 // Framework : 사용방법을 미리 정해 놓은 라이브러리 // List, Set, Map 인터페이스 구현 클래스가 존재 // List : ArrayList, Vector, LinkedList // Set : HashSet, TreeSet // Map : HashMap, Hashtable, TreeMap, Properties List<String> list = new ArrayList<String>(); list.add("사과"); String str = list.get(0); // Type 을 변환하지 않는다. System.out.println(str); List<Dog> animals = new ArrayList<Dog>(); animals.add(new Dog()); animals.add(new Dog()); //animals.add(new Cat()); // Cat을 넣으려고 하면 컴파일 시점에 타입 체크를 해주기 때문에 에러 발생 doAction(animals); }
}
|
여러 블로그 자료를 참조하고 동영상 강좌를 들으면서 정리하고 있는데 아직 완벽한 이해는 못한 상태다.
기본 개념은 이 자료로 이해는 된다. 하지만 깊이 있게 들어가는 사항은 좀 더 테스트를 하고 이해해야 한다.