# 제네릭 : 제네릭(Generic)은 클래스 내부에서 사용할 자료형을 나중에 인스턴스를 생성할 때 확정한다.
제네릭을 사용하면 객체의 자료형을 컴파일할 때 체크하기 떄문에 객체 자료형의 안정성을 높이고 형 변환의 번거로움이 줄어든다. 의도하지 않은 자료형의 객체를 지정하는 것을 막고 객체를 사용할 때 원래의 자료형에서 다른 자료형으로 형 변환 시 발생할 수 있는 오류를 줄인다.
package chap02.section1
/* 간단한 제네릭의 예제 */
class Box<T>(t: T) { // 형식 매개변수로 받은 인자를 name에 저장
var name = t
}
fun main() {
val box1 : Box<Int> = Box<Int>(1) // 인스턴스 생성 시 Int형으로 자료형이 결정됨
val box2 : Box<String> = Box<String>("Hello") // 인스턴스 생성 시 String형으로 자료형이 결정됨
println(box1.name)
println(box2.name)
}
/* Box<T>에서 T가 바로 형식 매개변수 이름이다. 보통 Type을 줄인 T를 사용하지만,
* 꼭 T를 사용하지는 않는다.
* 그 밖에 제네릭에서 사용하는 형식 매개변수 이름들 :
* E (요소 - Element)
* K (키 - Key)
* N (숫자 - Number)
* T (형식 - type)
* V (값 - Value)
* S,U,V etc. (2번째,3번째,4번째 형식)
* */
# 제네릭 클래스의 자료형 변환
package chap02.section1
/* 제네릭 클래스의 자료형 변환하기 */
open class Parent
class Child : Parent()
class Cup<T>
fun main() {
val obj1 : Parent = Child() // Parent 형식의 obj1은 Child의 자료형으로 변환될 수 있음
val obj2 : Child = Parent() // 자료형 불일치!
val obj3 : Cup<Parent> = Cup<Child>() // 자료형 불일치!
val obj4 : Cup<Child> = Cup<Parent>() // 자료형 불일치!
val obj5 = Cup<Child>() // obj5는 Cup<Child>의 자료형이 됨
val obj6 : Cup<Child> = obj5 // 자료형 일치!
}
# 형식 매개변수에 null이 가능한 제네릭 클래스
package chap02.section1
/* 제네릭 클래스의 자료형 변환하기 */
class GenericNull<T> { // 기본적으로 null이 허용되는 형식 매개변수
fun EqualityFunc(arg1: T, arg2: T) {
println(arg1?.equals(arg2))
}
}
fun main() {
val obj = GenericNull<String>() // non-null로 선언됨
obj.EqualityFunc("Hello","World") // null이 허용되지 않음
val obj2 = GenericNull<Int?>() // null이 가능한 형식으로 선언됨
obj2.EqualityFunc(null,20) // null 사용 가능
}
package chap02.section1
/* 제네릭 클래스의 자료형 변환하기 */
class GenericNull<T:Any> { // 자료형 Any가 지정되어 null을 허용하지 않음
fun EqualityFunc(arg1: T, arg2: T) {
println(arg1?.equals(arg2))
}
}
fun main() {
val obj = GenericNull<String>() // non-null로 선언됨
obj.EqualityFunc("Hello","World") // null이 허용되지 않음
val obj2 = GenericNull<Int?>() // 오류! null 허용이 안됨
obj2.EqualityFunc(null,20)
}
# 제네릭 함수
package chap02.section1
// 제네릭 함수(메서드)
/* 배열의 인덱스 찾아내기 */
// 제네릭 함수 선언
// a : Array<T> (자료형 아무거나 받을 수 있음)
// Target : T (자료형 아무거나 받을 수 있음)
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("Apple","Banana","Cherry","Durian")
val arr2: Array<Int> = arrayOf(1,2,3,4)
println("arr.indices ${arr1.indices}") // indices는 배열의 유효 범위 반환
println(find<String>(arr1,"Cherry")) // 요소 Cherry의 인덱스 찾아내기
println(find(arr2,2)) // 요소 2의 인덱스 찾아내기
println(find(arr1,"orange")) // 요소 orange의 인덱스 찾아내기 -> orange라는 요소가 없기 때문에 -1 반환
}
# 제네릭과 람다식
package chap02.section1
/* 제네릭과 람다식 */
fun <T> add(a: T, b: T, op : (T, T) -> T): T {
return op(a,b)
}
fun main() {
val result = add(2,3) { a, b -> a + b }
println(result)
/* 람다식 { a,b -> a + b}은 add() 함수가 실행될 때 넘겨지는 인자이므로
* 연산식을 함수 선언부에 직접 구현하지 않고 전달하는 방법을 사용한다. 따라서 함수의 형식 매개변수의 자료형을
* 특정하지 않아도 실행이 가능한 것이다.
* */
}
# 자료형 제한하기
package chap02.section1
/* 클래스 및 함수에서 형식 매개변수의 자료형 제한하기 */
// 자료형을 숫자형으로 제한하기
// Number : Int, Double, Long..과 같은 숫자형
class Calc<T: Number> { // 클래스의 형식 매개변수 제한
fun plus(arg1 : T, arg2 : T) : Double {
return arg1.toDouble() + arg2.toDouble()
}
}
// 함수에서 형식 매개변수의 자료형 제한하기(Number로 제한함)
fun <T: Number> addLimit(a: T, b: T, op : (T,T) -> T) : T {
return op(a,b)
}
fun main() {
val calc = Calc<Int>()
println(calc.plus(10,20))
val calc2 = Calc<Double>()
val calc3 = Calc<Long>()
//val calc4 = Calc<String> // 제한된 자료형으로 인해 오류 발생
println(calc2.plus(2.5,3.2))
println(calc3.plus(21L,12L))
//val result = addLimit("abc","def") { a, b -> a + b } // 제한된 자료형으로 인해 오류 발생
val result1 = addLimit(1,2) {a,b -> a + b}
}
# 다수 조건의 형식 매개변수 제한하기
package chap02.section1
interface InterfaceA
interface InterfaceB
class HandlerA : InterfaceA,InterfaceB
class HandlerB : InterfaceA
class ClassA<T> where T: InterfaceA, T:InterfaceB // 2개의 인터페이스를 구현하는 클래스로 제한
fun main() {
val ob1 = ClassA<HandlerA>() // 객체 생성 가능
val ob2 = ClassA<HandlerB>() // 범위에 없으므로 에러 발생!
}
/**/
'Kotlin' 카테고리의 다른 글
Kotlin - 컬렉션 (0) | 2022.06.21 |
---|---|
Kotlin - 배열 (0) | 2022.06.20 |
Kotlin - 여러 연산자들의 표현 (0) | 2022.06.20 |
Kotlin - 데이터 클래스(Java의 POJO)와 기타클래스 (0) | 2022.06.17 |
Kotlin - 추상클래스와 인터페이스 ★ (0) | 2022.06.15 |