├── .gitignore ├── .idea ├── .gitignore ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── kotlinc.xml ├── libraries │ └── KotlinJavaRuntime.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── belajar-kotlin-generic.iml └── src ├── app ├── ComparableInterface.kt ├── Contravariant.kt ├── Covariant.kt ├── GenericClass.kt ├── GenericConstraint.kt ├── GenericExtentionFunction.kt ├── GenericFunction.kt ├── Invariant.kt ├── ObservableProperty.kt ├── ReadOnlyProperty.kt ├── ReadWriteProperty.kt ├── StarProjection.kt ├── TypeErasure.kt └── TypeProjection.kt └── data ├── Fruit.kt ├── Function.kt └── MyData.kt /.gitignore: -------------------------------------------------------------------------------- 1 | out -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /.idea/libraries/KotlinJavaRuntime.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /belajar-kotlin-generic.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/app/ComparableInterface.kt: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import data.Fruit 4 | 5 | fun main() { 6 | val fruit1 = Fruit("Apple", 100) 7 | val fruit2 = Fruit("Apple", 10) 8 | 9 | println(fruit1 > fruit2) 10 | println(fruit1 >= fruit2) 11 | println(fruit1 < fruit2) 12 | println(fruit1 <= fruit2) 13 | } -------------------------------------------------------------------------------- /src/app/Contravariant.kt: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | class Contravariant{ 4 | fun sayHello(param: T){ 5 | println("Hello $param") 6 | } 7 | 8 | // tidak boleh 9 | // fun getData():T { 10 | // return data 11 | // } 12 | } 13 | 14 | fun main() { 15 | val contravariantAny = Contravariant() 16 | val contravariantString: Contravariant = contravariantAny 17 | 18 | // contravariantString.getData() // error 19 | contravariantString.sayHello("Eko") 20 | } -------------------------------------------------------------------------------- /src/app/Covariant.kt: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | class Covariant(val data: T) { 4 | 5 | fun data(): T { 6 | return data 7 | } 8 | 9 | // tidak boleh membuat function dengan input generic covariant 10 | // fun setData(param: T){ 11 | // data = param 12 | // } 13 | 14 | } 15 | 16 | fun main() { 17 | val covariantString = Covariant("Eko") 18 | val covariantAny: Covariant = covariantString 19 | 20 | println(covariantAny.data()) 21 | 22 | // covariantAny.setData(100) tidak boleh 23 | } -------------------------------------------------------------------------------- /src/app/GenericClass.kt: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import data.MyData 4 | 5 | fun main() { 6 | val myDataString: MyData = MyData("Eko", 100) 7 | myDataString.printlnData() 8 | 9 | val myDataInt = MyData(100, "Eko") 10 | myDataInt.printlnData() 11 | } -------------------------------------------------------------------------------- /src/app/GenericConstraint.kt: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | interface CanSayHello { 4 | fun sayHello(name: String) 5 | } 6 | 7 | open class Employee 8 | 9 | class Manager : Employee() 10 | 11 | class VicePresident : Employee(), CanSayHello { 12 | override fun sayHello(name: String) { 13 | println("Hello $name, I'm vice president") 14 | } 15 | } 16 | 17 | class Company(val employee: T) where T : Employee, T : CanSayHello 18 | 19 | fun main() { 20 | // val data1 = Company(Employee()) // error CanSayHello 21 | // val data2 = Company(Manager()) //error CanSayHello 22 | val data3 = Company(VicePresident()) 23 | // val data4 = Company("String") // error not Employee 24 | } -------------------------------------------------------------------------------- /src/app/GenericExtentionFunction.kt: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | class Data(val data: T) 4 | 5 | fun Data.print(){ 6 | val data: String = this.data 7 | println(data) 8 | } 9 | 10 | fun Data.printInt(){ 11 | val data: Int = this.data 12 | println(data) 13 | } 14 | 15 | fun main() { 16 | val data1 = Data(1) 17 | val data2 = Data("Eko") 18 | 19 | // data1.print() // error 20 | data2.print() 21 | data1.printInt() 22 | } -------------------------------------------------------------------------------- /src/app/GenericFunction.kt: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import data.Function 4 | 5 | fun main() { 6 | val function = Function("Eko") 7 | 8 | function.sayHello("Joko") 9 | function.sayHello("Joko") 10 | 11 | function.sayHello(10) 12 | function.sayHello(10) 13 | } -------------------------------------------------------------------------------- /src/app/Invariant.kt: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | class Invariant(var data: T) 4 | 5 | fun main() { 6 | val invariantString = Invariant("String") 7 | 8 | // val invariantAny: Invariant = invariantString // bisa 9 | // invariantAny.data = 100 // bahaya 10 | } -------------------------------------------------------------------------------- /src/app/ObservableProperty.kt: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import kotlin.properties.Delegates 4 | import kotlin.properties.ObservableProperty 5 | import kotlin.reflect.KProperty 6 | 7 | class LogObservableProperty(param: T) : ObservableProperty(param){ 8 | 9 | override fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean { 10 | println("Before change ${property.name} from $oldValue to $newValue") 11 | return true 12 | } 13 | 14 | override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) { 15 | println("After change ${property.name} from $oldValue to $newValue") 16 | } 17 | 18 | } 19 | 20 | class Car(brand: String, year: Int){ 21 | var brand: String by LogObservableProperty(brand) 22 | var year: Int by LogObservableProperty(year) 23 | var owner: String by Delegates.notNull() 24 | var description: String by Delegates.vetoable(""){ property, oldValue, newValue -> 25 | println("Before change ${property.name} from $oldValue to $newValue") 26 | true 27 | } 28 | var other: String by Delegates.observable(""){ property, oldValue, newValue -> 29 | println("After change ${property.name} from $oldValue to $newValue") 30 | } 31 | } 32 | 33 | fun main() { 34 | var car = Car("Toyota", 2019) 35 | 36 | car.brand = "Wuling" 37 | println(car.brand) 38 | 39 | car.year = 2020 40 | println(car.year) 41 | 42 | car.owner = "Eko" 43 | println(car.owner) 44 | 45 | car.description = "Desc" 46 | println(car.description) 47 | 48 | car.other = "Other" 49 | println(car.other) 50 | 51 | } -------------------------------------------------------------------------------- /src/app/ReadOnlyProperty.kt: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import kotlin.properties.ReadOnlyProperty 4 | import kotlin.reflect.KProperty 5 | 6 | class LogReadOnlyProperty(val data: String): ReadOnlyProperty { 7 | var counter: Int = 0 8 | override fun getValue(thisRef: Any, property: KProperty<*>): String { 9 | println("Access property ${property.name} with value $data") 10 | counter++ 11 | return "$counter.${data.toUpperCase()}" 12 | } 13 | } 14 | 15 | class NameWithLog(param: String){ 16 | val name: String by LogReadOnlyProperty(param) 17 | } 18 | 19 | fun main() { 20 | val nameWithLog = NameWithLog("Eko Kurniawan") 21 | println(nameWithLog.name) 22 | println(nameWithLog.name) 23 | } -------------------------------------------------------------------------------- /src/app/ReadWriteProperty.kt: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import kotlin.properties.ReadWriteProperty 4 | import kotlin.reflect.KProperty 5 | 6 | class StringLogReadWriteProperty(var data: String) : ReadWriteProperty{ 7 | override fun getValue(thisRef: Any, property: KProperty<*>): String { 8 | println("Get property ${property.name} with value $data") 9 | return data 10 | } 11 | 12 | override fun setValue(thisRef: Any, property: KProperty<*>, value: String) { 13 | println("Set property ${property.name} from $data to $value") 14 | data = value 15 | } 16 | } 17 | 18 | class Person(param: String){ 19 | var name: String by StringLogReadWriteProperty(param) 20 | } 21 | 22 | fun main() { 23 | val person = Person("Eko") 24 | 25 | println(person.name) 26 | 27 | person.name = "Kurniawan" 28 | 29 | println(person.name) 30 | } -------------------------------------------------------------------------------- /src/app/StarProjection.kt: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | fun displayLength(array: Array<*>) { 4 | println("Total array is ${array.size}") 5 | } 6 | 7 | fun main() { 8 | val arrayInt: Array = arrayOf(1, 2, 3, 4, 5) 9 | val arrayString: Array = arrayOf("Eko", "Kurniawan", "Khannedy") 10 | 11 | displayLength(arrayInt) 12 | displayLength(arrayString) 13 | } -------------------------------------------------------------------------------- /src/app/TypeErasure.kt: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | class TypeErasure(param: T){ 4 | private val data: T = param 5 | fun getData(): T = data 6 | } 7 | 8 | fun main() { 9 | val data1 = TypeErasure("Eko") 10 | val dataString: String = data1.getData() 11 | println(dataString) 12 | 13 | val data2: TypeErasure = data1 as TypeErasure 14 | val dataInt = data2.getData() // error konversi 15 | println(dataInt) 16 | } -------------------------------------------------------------------------------- /src/app/TypeProjection.kt: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | class Container(var data: T) 4 | 5 | fun copyContainer(from: Container, to: Container) { 6 | to.data = from.data 7 | } 8 | 9 | fun main() { 10 | val container1 = Container("Eko") 11 | val container2: Container = Container("Kurniawna") 12 | 13 | copyContainer(container1, container2) 14 | 15 | println(container1.data) 16 | println(container2.data) 17 | } -------------------------------------------------------------------------------- /src/data/Fruit.kt: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | class Fruit(val name: String, val quantity: Int) : Comparable { 4 | 5 | override fun compareTo(other: Fruit): Int { 6 | return quantity.compareTo(other.quantity) 7 | } 8 | } -------------------------------------------------------------------------------- /src/data/Function.kt: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | class Function(val name: String) { 4 | 5 | fun sayHello(param: T){ 6 | println("Hello $param, my name is $name") 7 | } 8 | 9 | } -------------------------------------------------------------------------------- /src/data/MyData.kt: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | class MyData(val firstData: T, val secondData: U) { 4 | 5 | fun getData(): T = firstData 6 | 7 | fun getSecond(): U = secondData 8 | 9 | fun printlnData(){ 10 | println("Data is $firstData $secondData") 11 | } 12 | 13 | } --------------------------------------------------------------------------------