[Java] Generics

toget ㅣ 2023. 10. 3. 11:28

Generics

Generics이란,Java에서 제공하는 타입 안정성과 재사용성을 높이기 위한 기능이며,
클래스, 메서드, 인터페이스 등에서 타입 매개변수를 사용하여 다양한 타입의 객체를 다룰 수 있게 합니다.

-주요 키워드
타입 매개변수 (Type Parameter)
제네릭에서 사용하는 변수로, 일반적으로 대문자 알파벳으로 표시되며 <T>와 같은 형태로 표현.
실제 타입은 인스턴스화 시에 결정됨.

제네릭 클래스 (Generic Class)
타입 매개변수를 사용하여 클래스를 정의한 것.
예: class MyGenericClass<T> { ... }

제네릭 메서드 (Generic Method)
메서드 내에서 타입 매개변수를 사용하는 메서드.
예: public <T> void myGenericMethod(T value) { ... }

와일드카드 (Wildcards)
? 기호를 사용하여 일부 제네릭 타입의 유연한 매개변수화를 지원.
상한 제한 와일드카드 (<? extends T>)와 하한 제한 와일드카드 (<? super T>) 등이 있음.

타입 변환 (Type Erasure)
컴파일 시에 제네릭 타입 정보를 제거하여 바이트 코드를 생성하는 과정.
제네릭 타입을 사용하면 컴파일러는 컴파일 시 타입 검사를 수행하고,

런타임에서는 타입 정보가 지워져 런타임에는 Object로 취급.

바운드 (Bounds)
제네릭 클래스나 메서드에서 허용되는 타입의 범위를 제한하는 기능.
상한 바운드 (extends)와 하한 바운드 (super)를 지정할 수 있음.

타입 Inference
컴파일러가 제네릭 메서드나 생성자 호출 시 실제 타입 인수를 추론하는 프로세스.
타입 인수를 명시적으로 지정하지 않아도 컴파일러가 타입을 추론.

타입 제약 조건 (Type Constraints)
타입 매개변수에 대한 특정 조건을 설정하여 특정 타입의 객체만 받도록 하는 제약.
예: <T extends Number>는 Number 클래스 또는 그 하위 클래스만 받도록 제약.

와일드카드 캡처 (Wildcard Capture)
와일드카드를 사용한 제네릭 메서드에서 와일드카드 타입을 캡처하여 실제 타입으로 사용하는 과정.

타입 경계 (Type Boundary)
제네릭 클래스나 메서드에서 타입 매개변수의 범위를 지정하는 것.
예: <T extends Comparable<T>>는 Comparable 인터페이스를 구현한 타입만 받도록 함.

이러한 키워드와 개념을 이해하고 활용하면 Java에서 제네릭을 사용하여 타입 안전성을 확보하고 유연한 코드를 작성할 수 있습니다.

 

예시 :제네릭스(Generics)를 사용 X

class Apple{}

class Goods1{
    private Apple apple= new Apple();
    public Apple GetApple() {
    	return apple;
	}
	public void SetApple(Apple apple) {
    	this.apple =apple;
    }
}

class Pencil{}

class Goods2{
    private Pencil pencil= new Pencil();
    public Pencil GetPencil(){
    	return pencil;
	}
    public void SetPencil(Pencil pencil) {
    	this.pencil =pencil;
	}
}

 

class Goods3{
private Object object=new Object();
   public Object Get() {
        return object;
    }
    public void Set(Object object) {
        this.object=object;
    }
}

 

위의 코드에서는 Goods1과 Goods2 클래스가 각각 Apple과 Pencil 객체를 저장하고 관리하는데, 새로운 종류의 상품을 추가할 때마다 새로운 클래스를 만들어야 합니다. 이는 확장성이 떨어지고 유지보수가 어려운 코드를 만들 수 있습니다.

 

 

 

예시 :제네릭스(Generics)를 사용

public class Goods<T> {
    private T item;
    public T get() {
   		return item;
	}
	public void set(T item) {
    	this.item = item;
     }
}
Goods<Apple> appleGoods = new Goods<>();
appleGoods.set(new Apple()); // Apple 객체 저장
Apple apple = appleGoods.get(); // Apple 객체 읽어오기

Goods<Pencil> pencilGoods = new Goods<>();
pencilGoods.set(new Pencil()); // Pencil 객체 저장
Pencil pencil = pencilGoods.get(); // Pencil 객체 읽어오기

이렇게 하면 코드의 일반성과 타입 안정성이 향상되며, 새로운 타입의 객체를 추가하더라도 기존 클래스를 수정할 필요가 없습니다.

제네릭을 사용하면 코드의 재사용성과 유지보수성을 높일 수 있으며, 타입 관련 에러를 컴파일 시간에 미리 감지하여 안정성을 확보할 수 있습니다.



참조

https://inpa.tistory.com/entry/JAVA-%E2%98%95-%EC%A0%9C%EB%84%A4%EB%A6%ADGenerics-%EA%B0%9C%EB%85%90-%EB%AC%B8%EB%B2%95-%EC%A0%95%EB%B3%B5%ED%95%98%EA%B8%B0#%EC%A0%9C%EB%84%A4%EB%A6%AD_generics_%EC%9D%B4%EB%9E%80