[코틀린 완전정복] 제네릭

제네릭

제네릭 , 다른 언어를 이미 경험하고 왔다면 낯선 단어는 아니다. 뭐 대충 얘기하면 자료형 을 나중에 선언하는? 그런 느낌이다. 우선 확실하게 집고 넘어가보자.

그래서 제네릭이 뭐고 왜 쓰는거에요? 🤔

제네릭 은 클래스 내부에서 사용할 자료형을 나중에 인스턴스를 생성할 때 확정하는 방법이다. 제네릭이 나오게 된 배경은 자료형의 객체들을 다루는 메소드나 클래스에서 컴파일 시간에 자료형을 검사하여 적당한 자료형을 선택하기 위해서이다. 제네릭을 사용하면 객체의 자료형을 컴파일할 때 체크하기 때문에 객체 자료형의 안정성을 높이고 형 변환의 번거로움이 줄어든다.

제네릭의 사용 방법

제네릭은 앵글 브래킷 <> 사이에 형식 매개변수 를 넣어 선언하고 하나 이상의 형식 매개변수를 지정할 수 있다. 형식 매개변수는 자료형을 대표하는 용어로 T와 같은 특정 영문자를 사용하여 나중에 필요한 자료형으로 대체한다. 보통 컬렉션 에 많이 사용한다.

class Box<T> (t : T) {
	var name = t
}

fun main() {
	val box1 : Box<Int> = Box<Int>(1)
	val box2 : Box<String = Box<String>("kodo")
	// 타입 추론이 가능하므로 자료형 생략 가능
	// val box1 = Box<Int>(1)
	// val box2 = Box<String>("kodo")
	println(box1.name)
	println(box2.name)
}

Box 클래스를 제네릭을 사용해서 정의했다. 위 코드를 실행하면 아래와 같은 결과가 출력된다.

1
kodo

제네릭을 사용하면 객체를 생성할 때 자료형의 타입을 결정한다. 따라서 인자의 자료형을 고정할 수 없거나 예측할 수 없을 때 사용하면 실행시간에 자료형을 결정할 수 있게 되므로 유용하다.

제네릭 메소드

제네릭 을 형식 매개변수로 받는 메소드를 제네릭 메소드라고 한다.

fun <T> genericFun(arg : T) : T? { }
fun <K , V> put(key : K, value : V) : Unit { }

아래 코드는 배열에서 특정 원소의 인덱스를 찾아내는 코드이다.

fun <T> find(a : Array<T>, Target : T) : Int {
	for (i in a.indices) {
		if (a[i] == Target) return i
	}
	return -1
}

fun main() {
	val arr1 : Array<String> = arrayOf("사과", "바나나", "수박", "멜론")
	println(find<String>(arr1, "사과"))
}

자료형 제한하기

제네릭 클래스나 메소드가 받는 형식 매개변수를 특정한 자료형으로 제한할 수도 있다. 형식 매개변수 다음에 콜론(:)과 자료형을 기입하면 형식 매개변수의 자료형이 된다.

class Calc<T : Number> {
	fun plus(arg1 : T, arg2 : T) : Double {
		return arg1.toDouble() + arg2.toDouble()
	}
}

fun main() {
	val calc1 = Calc<Int>()
	println(calc1.plus(10, 10))

	val calc2 = Calc<Double>()
	println(calc2.plus(5.0, 5.0))
	
	val calc3 = Calc<String>() // 오류!

좋은 웹페이지 즐겨찾기