제네릭, Generic
데이터 타입을 일반화(generalize)한다.
클래스나 메서드에서 사용할 데이터 타입을 컴파일 시에 미리 지정하는 방법
장점:
- 타입 안전성: 컴파일 시점에 타입 체크를 수행해서 런타임 오류 방지 > 에러를 미연에 방지
- 재사용성: 일반화된 타입 > 여러 종류의 객체를 처리할 수 있다.
- 가독성: 타입 정보가 미리 명시되어 코드를 이해하기 쉽다. 코드 의도가 명확 > 가독성이 좋아진다.
- 컴파일 시에 미리 타입이 지정되므로, 타입 검사나 타입 변환과 같은 추가 작업을 생략할 수 있다.
제네릭 타입
클래스나 인터페이스를 선언할 때 타입 매개변수 T를 사용해서 일반화 타입을 지정한다.
T : 타입 변수, 일반화 타입 (wrapper 클래스이면 어떤 타입이든 받을 수 있음)
- 클래스를 제네릭 타입으로 선언 > 이후 객체 생성 시 타입을 구체화해서 사용 (실제 타입 명시)
- 제네릭 클래스를 사용할 때 실제 타입을 명시 > 타입 변수 T가 실제 타입으로 변환되어 처리된다.
class MyArray<T> {
T element;
void setElement(T element) {
this.element = element;
}
T getElement() {
return element;
}
}
// 사용
MyArray<Integer> myArr = new MyArray<Integer>();
MyArray<String> myArr = new MyArray<String>();
ex)
public class Box<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
private T getItem() {
return item;
}
public static void main(String[] args) {
// Box<int> boxInt = new Box<>(); // error
Box<Integer> box = new Box<>();
box.setItem(10);
// box.setItem("문자열"); // error > Integer로 선언했기 때문에 String을 넣으면 에러
int tmp = box.getItem(); // 형 변환 없이 정수형 결과 반환
Box<String> boxStr = new Box<>();
boxStr.setItem("lion");
String tmpStr = boxStr.getItem(); // 형 변환 없이 문자열 결과 반환
}
}
제네릭 메서드
메서드 선언시 매개변수나 반환값의 타입에 타입 변수를 사용한 메소드
타입 변수 선언은 메소드 선언부에서 반환 타입 바로 앞에 위치한다.
- 제네릭 메서드를 사용할 때 전달되는 인자에 따라 메서드가 동작 > 다양한 타입의 인자, 반환값을 처리할 수 있다.
public static <T> T genericMethod( <T> T ) {
// logic
}
ex)
// 제네릭 메소드
// T 타입에 상관 없이 같은 동작을 보장
public static <T> T getFirstItem(List<T> list) {
if (list.isEmpty()) {
return null;
} else {
return list.get(0);
}
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
int firstItem = getFirstItem(list);
}
제네릭 클래스의 T와 제네릭 메서드의 T는 다른 것!
class genelicClass<T> {
...
public static <T> void genelicMethod(List<T> list) {
...
}
}
cf) 와일드 카드 사용
참고: http://www.tcpschool.com/java/java_generic_various
- <?> : 타입 변수에 모든 타입 사용 가능
- <? extends T> : T 타입과 T 타입을 상속하는 자식 클래스 타입만 사용 가능
- <? super T> : T 타입과 T 타입이 상속받은 부모 클래스 타입만 사용 가능
ex)
package com.example.javaproject.week6.day5;
import java.util.*;
class LandAnimal { public void crying() { System.out.println("육지동물"); } }
class Cat extends LandAnimal { public void crying() { System.out.println("냐옹냐옹"); } }
class Puppy extends LandAnimal { public void crying() { System.out.println("멍멍"); } }
class Sparrow { public void crying() { System.out.println("짹짹"); } }
class AnimalList<T> {
ArrayList<T> al = new ArrayList<T>();
// LandAnimal과 LandAnimal을 상속받은 Cat, Dog 이 인자로 올 수 있다.
public static void cryingAnimalList(AnimalList<? extends LandAnimal> al) {
LandAnimal la = al.get(0);
la.crying();
}
void add(T animal) { al.add(animal); }
T get(int index) { return al.get(index); }
boolean remove(T animal) { return al.remove(animal); }
int size() { return al.size(); }
}
public class WildCardTest {
public static void main(String[] args) {
AnimalList<Cat> catList = new AnimalList<Cat>();
catList.add(new Cat());
AnimalList<Puppy> dogList = new AnimalList<Puppy>();
dogList.add(new Puppy());
AnimalList.cryingAnimalList(catList);
AnimalList.cryingAnimalList(dogList);
AnimalList<Sparrow> spList = new AnimalList<Sparrow>();
spList.add(new Sparrow());
// AnimalList.cryingAnimalList(spList); // error > Sparrow는 LandAnimal를 상속받지 않았기 때문에 해당 메소드를 사용할 수 없다.
}
}
cf) Wrapper Class
기본 타입 데이터를 객체로 취급해야 하는 경우, 기본 타입의 데이터를 객체로 포장해 주는 클래스
- wrapper class는 각 타입에 해당하는 데이터를 인수로 받음 > 해당 값을 가지는 객체 반환
- wrapper class 인스턴스에 저장된 값은 변경할 수 없다. > 값 참조만 가능
- java.lang 패키지에서 제공
- Boxing : 기본 타입 → wrapper class / UnBoxing : wrapper class → 기본 타입
기본 타입 wrapper class
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
'CS > Backend' 카테고리의 다른 글
[MySQL] WINDOW 함수 (0) | 2023.05.26 |
---|---|
[MySQL] JOIN (0) | 2023.05.26 |
[Java] 추상 클래스, 인터페이스 (0) | 2023.05.26 |
[MySQL] EXTRACT(part FROM date) (0) | 2023.05.26 |
[MySQL] 집계 함수, GROUP BY (0) | 2023.05.26 |