제네릭 사용법
제네릭은 잘못된 타입이 사용 될 수 있는 문제를 컴파일 과정에서 제거할 수 있다. 자바 컴파일러는 코드에서 잘못 사용된 타입 때문에 발생핳는 문제점을 제거하기 위해 제네릭 코드에 대해 강한 타입 체크를 한다. 그럼 제네릭 사용법에 대해 알아보겠다.
[제네릭 사용법]
public class 클래스명 <T> {...}
public interface 인터페이스명<T> {...}
제네릭 타입은 타입을 파라미터로 가지는 클래스와 인터페이스를 말한다. 위 코드와 같이 클래스 또는 인터페이스 이름 뒤에 <> 부호가 붙고 사이에 타입 파라미터가 위치한다. 또한 멀티 타입 파라미터 사용도 가능하다.
[멀티 타입 파라미터 사용법]
class 클래스명 <k,v> {...}
[타입 파라미터]
꺾새 사이에 들어가는 타입 파라미터의 종류에 대해 살펴보자.
<T> | Type |
<E> | Element |
<K> | Key |
<N> | Number |
<V> | Value |
<R> | Result |
ex)
// 제네릭 클래스
class Animal <T> {
private T t;
public void setT(T t)
{
this.t = t;
}
public T getT() {
return t;
}
}
// 제네릭 인터페이스
interface Animal <T> {
T example();
}
class ex implements Animal<String>{
@Override
public String example() {
return null;
}
}
// 멀티 타입 파라미터 사용
import java.util.Map;
class exam <K, V> implements Map.Entry<K,V>{
private K key;
private V value;
@Override
public K getKey(){
return this.key;
}
@Override
public V getValue() {
return this.value;
}
@Override
public V setValue(V value) {
this.value = value;
return value;
}
}
제네릭 주요 개념 (바운디드 타입, 와일드 카드)
1) 바운디드 타입
이는 제네릭 타입의 범위를 제한 할 수 있다. 제네릭 타입에 extends를 사용하면 특정 타입의 자손들만 대입할 수 있게 제한이 가능하다. 여기서 extends는 클래스의 extends 또는 인터페이스의 implements 처럼 구현한다는 것은 아니다.
예제를 살펴보겠다.
ex)
class Test <T extends Number > {
T element;
void setTest(T element) {
this.element = element;
}
T getElement() {
return element;
}
}
2) 와일드 카드
와일드 카드는 이름에 제한을 두지 않음을 표현하는 데 사용되는 기호를 의미한다. 와일드 카드에는 총 세 가지 형태가 있으며 (?)라는 키워드로 표현된다.
제네릭타입<?> 은 타입 파라미터를 대치하는 것으로 모든 클래스나 인터페이스 타입이 올 수 있다.
제네릭타입<? extends 상위타입> | 와일드카드의 범위를 특정 객체의 하위 클래스만 올 수 있다. (bounded) |
제네릭타입<? super 하위타입> | 와일드카드의 범위를 특정 객체의 상위 클래스만 올 수 있다. (bounded) |
제네릭타입<? extends A & B & C> | 와일드카드의 범위를 명시된 다수 객체의 하위 클래스로 제한한다. |
ex)
import java.util.ArrayList;
class Animal {
public void cry() {
System.out.println("동물");
}
}
class Cat extends Animal{
public void cry() {
System.out.println("냐옹");
}
}
class Dog extends Animal {
public void cry() {
System.out.println("멍멍");
}
}
class WildCard<T>{
ArrayList<T> a = new ArrayList<T>();
public static void crying(WildCard<? extends Animal > list) {
Animal b = list.get(0);
b.cry();
}
void add(T animal ){
a.add(animal);
}
T get (int index) {
return a.get(index);
}
}
public class Main {
public static void main(String[] args) {
WildCard<Cat> catList = new WildCard<Cat>();
WildCard<Dog> dogList = new WildCard<Dog>();
catList.add(new Cat());
dogList.add(new Dog());
WildCard.crying(catList);
WildCard.crying(dogList);
}
}
제네릭 메소드 만들기
제네릭 메소드는 메소드의 선언부 타입 변수를 사용한 메소드로 제네릭 메소드 형태는 다음과 같다.
public static <T> void method() {}
ex)
// 제네릭 메소드
class Animal<T, M> {
private T name;
private M sound;
Animal ( T name , M sound){
this.name = name;
this.sound = sound;
}
public T getName() {
return name;
}
public void setName (T name){
this.name = name;
}
public M getSound(){
return sound;
}
public void setSound( M sound){
this.sound = sound;
}
public static <T,V> boolean compare(Animal<T,V> p1, Animal<T,V> p2){
boolean nameCompare = p1.getName().equals(p2.getName());
boolean soundCompare =p1.getSound().equals(p2.getSound());
return nameCompare && soundCompare;
}
}
public class Main
public static void main(String []args){
Animal<String,Integer> p1 = new Animal(String,Integer>("cat",111);
Animal<String,Integer> p2 = new Animal("hippo",222);
boolean result = p1.compare(p1,p2);
System.out.println(result);
}
}
Erasure
type erasure : 컴파일 타입에만 타입 제약 조건을 정의하고, 런타임에는 타입을 제거한다. 즉 컴파일 이후에는 제네릭 타입이 존재하지 않고 , Object 또는 상한 제한 (bound)으로 변환된다. 이를 통해 매개변수화 된 타입에 대해 새로운 클래스가 생성되지 않게 하여 런타임 오버헤드 발생을 막는다.
ex)
타입 소거 전후를 비교해보겠다.
[제네릭을 사용한 코드]
class Animal<T> {
private T name;
public void setName( T name){
this.name = name;
}
public Object getName() {
return name;
}
}
[컴파일 이후 변환된 코드(타입 소거)]
class Animal
private Object name;
public void setName( Object name){
this.name = name;
}
public Object getName() {
return name;
}
}
위 결과를 살펴보면 T가 Object로 변환되는 것을 볼 수 있다. 제네릭 타입이 사라져 런타임에는 타입 정보가 존재하지 않게 된다.
[참고 자료]
https://coding-factory.tistory.com/573
[Java] 제네릭(Generic) 사용법 & 예제 총정리
제네릭을 사용해야하는 이유 제네릭 타입을 사용함으로써 잘못된 타입이 사용될 수 있는 문제를 컴파일 과정에서 제거할 수 있기 때문입니다. 자바 컴파일러는 코드에서 잘못 사용된 타입 때문
coding-factory.tistory.com
https://velog.io/@bokimy/Java%EC%A0%9C%EB%84%A4%EB%A6%AD-%EC%82%AC%EC%9A%A9%EB%B2%95
[Java]제네릭 사용법
제네릭(Generic) 클래스나 메서드의 코드를 작성할 때, 타입을 정해두는 것이 아니라 추후에 지정할 수 있도록 일반화해두는 것. = 작성한 클래스나 메서드의 코드가 특정 데이터 타입에 얽매이지
velog.io
https://xcv20123.tistory.com/39
9주차 : 제네릭
제네릭 사용법 ■ 제네릭이란? Java에서 데이터 타입을 일반화하는 것을 의미 제네릭은 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시 지정 ■ 제네릭을 사용하는 이유 클래스나 메
xcv20123.tistory.com
https://acver.tistory.com/entry/JAVA-%EC%A0%9C%EB%84%A4%EB%A6%AD
[JAVA] 제네릭
제네릭 사용법 제네릭을 사용해야 하는 이유 제네릭 타입을 사용함으로써 잘못된 타입이 사용될 수 있는 문제를 컴파일 과정에서 제거할 수 있다. 제네릭 코드를 사용하면 타입을 국한하기 때
acver.tistory.com
'🦁아기사자' 카테고리의 다른 글
[Java] 람다식 (0) | 2025.04.01 |
---|---|
[Java] I/O (0) | 2025.03.31 |
[Java] 애노테이션 (0) | 2025.03.27 |
[Java] Enum (0) | 2025.03.26 |
[Java] 멀티스레드 프로그래밍 (0) | 2025.03.25 |