다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입 체크(Compile-Time Type Check)를 해주는 기능.
인스턴스 별로 다르게 동작하도록 하려고 만든 기능.
다룰 객체의 타입을 미리 명시해줌으로써 번거로운 형변환을 줄여준다.
지네릭스를 모르고는 Java API 문서조차 제대로 보기 어려울 만큼 중요하다.
장점
타입 안전성 제공
타입 체크와 형변환을 생략할 수 있어 코드가 간결해 진다.
지네릭 클래스의 객체 생성
참조 변수와 생성자에 타입 T 대신에 사용될 실제 타입을 지정한다.
어떤 타입이든 한 가지 타입을 정해서 담을 수 있다.
Test<String>test=newTest<String>();test.setItem("love");test.setItem(newObject());// error. 지정된 타입만 가능.Stringitem=test.getItem();
생성자의 타입은 참조 변수의 타입으로 추정 가능할 경우 생략할 수 있다. (JDK1.7부터)
Test<String>test=newTest<>();
참조 변수와 생성자에 대입된 타입이 일치해야 한다.
Test<String>test=newTest<Integer>();// error
두 타입이 상속 관계에 있더라도 대입된 타입이 다르다고 간주된다.
// class Animal {}// class Dog extends Animal{}Test<Animal>test=newTest<Animal>();Test<Animal>test=newTest<Dog>();// error
두 지네릭 클래스의 타입이 상속관계에 있고, 대입된 타입이 같으면 괜찮다.
// class Test01<T> extends Test<T> {}// class Animal {}// class Dog extends Animal{}Test<Animal>test=newTest01<Animal>();Test<Dog>test=newTest01<Dog>();Test<Animal>test=newTest01<Dog>();// error
타입을 지정하지 않을 경우, 지네릭 타입을 지정하지 않아서 안전하지 않다는 경고가 발생한다.
Testtest=newTest();// T → Objecttest.setItem("love");// (Java)unchecked or unsafe operations./(Android)unchecked call to "setImte(T)" as a member of raw typeStringitem=(String)test.getItem();
용어
Test<String> test = new Test<String>();
Test<대입된 타입> test = new Test<String>();
지네릭 타입 호출 test = new 지네릭 타입 호출();
Test<String>
지네릭 타입 호출. 타입 매개변수에 타입을 지정하는 것
String
대입된 타입. 매개변수화된 타입 Parameterized Type. 타입 매개변수에 지정된 타입
지네릭 클래스의 사용
Test<T>의 객체에 setItem(T item)으로 객체를 추가할 때, 대입된 타입과 다른 타입의 객체는 추가할 수 없다.
!! 지네릭 클래스에 정의된 타입 매개변수와 지네릭 메서드에 정의된 타입 매개변수는 전혀 별개의 것이다.
→ 지네릭 클래스가 아닌 클래스에도 정의될 수 있다.
→ 메서드가 static이건 아니건 상관 없다.
→ 내부 클래스에 선언된 타입 문자가 외부 클래스의 타입 문자와 같아도 구별된다.
classToy{static<T>voidmethod(List<T>list){}}
이전 글에 나왔던 makeJuice()를 지네릭 메서드로 바꾸면 다음과 같다.
// before staticJuicemakeJuice(FruitBox<?extendsFruit>box){Stringtmp="";for(Fruitf:box.getList()){tmp+=f+" ";}returnnewJuice(tmp);}// afterstatic<TextendsFruit>JuicemakeJuice(FruitBox<T>box){Stringtmp="";for(Fruitf:box.getList()){tmp+=f+" ";}returnnewJuice(tmp);}
매개변수의 타입이 복잡할 때 유용하다. → 타입을 별도로 선언.
// before staticvoidmethod(ArrayList<?extendsA>list,ArrayList<?extendsA>list2){}// afterstatic<TextendsA>voidmethod2(ArrayList<T>list,ArrayList<T>list2){}