열거 클래스는 다음과 같이 선언하여, 사용할 수 있다.

또한 기본으로 다음과 같은 멤버 및 멤버 함수를 가지고 있다.

 

val name:String

val ordinal:Int

fun valueOf(value:String): 열거 클래스

fun values():Array<열거 클래스>

 

여기서 name 은 열거 클래스에서 작성한 문자열 그대로 표기되며, 또한 ordinal은 첫번째 열거 부터 시작하여, 0 에서 시작하고 해당 열거 부분의 Index 값을 가지고 있다.

enum class Mode
{
	SELECTION, PEN, SHAPE, ERASER
}

fun main(args: Array<String>)
{
	// 현재 선택된 모드
	val mode: Mode = Mode.PEN

	when (mode)
	{
		Mode.SELECTION -> println("선택 모드")
		Mode.PEN -> println("펜 모드")
		Mode.SHAPE -> println("도형 모드")
		Mode.ERASER -> println("지우개 모드")
	}
}

열거 클래스에 프로퍼티와 멤버 함수 선언하는 방법

enum class Mode(val number: Int)
{
	SELECTION(0),
	PEN(1),
	SHAPE(2),
	ERASER(3);

	fun printNumber()
	{
		println("모드: $number")
	}
}

fun main(args: Array<String>)
{
	// 현재 선택된 모드
	val mode: Mode = Mode.ERASER

	println(mode.number)
	mode.printNumber()
}

참고 : 초보자를 위한 Kotlin 200제 라는 책을 기반으로 공부 내용을 정리하였습니다

in/out 키워드는 타입 매개변수의 업 및 다운 캐스팅을 할 수 있도록 지원되는 키워드이다.

out : AAA<서브 타입>을 AAA<Super 타입>에 대입할 수 있도록 지원.

in : AAA<Super 타입>을 AAA<서브 타입>에 대입할 수 있도록 지원.

* : AAA<*> 은 타입 인수가 무엇이든 상관없이 대입 할 수 있도록 지원.

class AAA<out T>

class BBB<in T>

fun main(args: Array<String>)
{
	val aaaSub = AAA<Int>()
	val aaaSuper: AAA<Any> = aaaSub

	val bbbSuper = BBB<Any>()
	val bbbSub: BBB<Int> = bbbSuper

	val star: AAA<*> = aaaSub
}

.. 연산자는 범위를 표현하는 연산자 이다.

.. 연산자는 operator fun rangeTo 라는 함수로 치환된다.

만약 클래스를 정의 하고 하고 싶을 경우, operator fun rangeTo 라는 함수를 오버라이딩하면 된다.

fun main(args: Array<String>)
{
	val oneToTen: IntRange = 1..10
	println(5 in oneToTen)

	val upperAtoZ: CharRange = 'A'..'Z'
	if ('C' in upperAtoZ)
		println("대문자입니다.")

	if ('p' in 'a'..'z')
		println("소문자입니다.")
}

 

 

참고 : 초보자를 위한 Kotlin 200제 라는 책을 기반으로 공부 내용을 정리하였습니다

타입 매개 변수는 대부분의 상황에서 일반 타입 처럼 사용할 수 있으나, 특정 상황에서는 불가능 하다.

예를 들면 is 키워드가 그렇다.

만약 is 키워드를 사용하고 싶다면, fun 앞에 inline을 붙여주어야 하며, 타입 매개 변수 앞에는 reified 키워드를 붙여주어야 한다.

inline fun <reified T> check()
{
	val number = 0
	if (number is T)
		println("T는 Int 타입 입니다.")
}

fun main(args: Array<String>)
{
	check<Int>()
}

참고 : 초보자를 위한 Kotlin 200제 라는 책을 기반으로 공부 내용을 정리하였습니다

함수 리터럴 : (Int)->Unit 은 매개변수가 Int타입이고, 반환타입이 Unit인 함수를 저장할 수 있는 타입을 뜻함.

람다식 : {매개변수 -> 반환 값} 형태를 이야기 함.

fun main(args: Array<String>)
{
	val instantFunc: (Int) -> Unit
	instantFunc = { number: Int ->
		println("Hello $number")
	}

	instantFunc(33)
	instantFunc.invoke(33)
}

위의 예제 코드에서 .invoke라는 함수가 있는데, 함수 타입의 변수를 해당 함수를 통하여, 호출해도 된다.

 

익명 함수 : 람다 식으로 표기된 함수 리터럴을 함수 이름이 없는 함수로 다르게 표현할 수 있다. 이를 익명함수라 한다. 

                fun{value type}:{return type}

fun main(args: Array<String>)
{
	val instantFunc: (Int) -> Unit
	instantFunc = fun(number: Int): Unit
	{
		println("Hello $number")
	}

	instantFunc(33)
	instantFunc.invoke(33)
}

it 식별자 : 람다식의 매개 변수가 하나일 경우, 매개 변수 선언을 생략할 수 있다. 그리고 그 매개 변수를 사용하고 싶을 때 사용되는 키워드이다.

fun main(args: Array<String>)
{
	val instantFunc: (Int) -> Unit = {
		println("Hello $it")
	}

	instantFunc(33)
}

 

참고 : 초보자를 위한 Kotlin 200제 라는 책을 기반으로 공부 내용을 정리하였습니다

sealed 키워드는 자신의 중첩 클래스에 한해서만 상속을 허용하는 키워드이다.

해당 내용에 대한 예제 코드는 다음과 같다.

sealed class Outer
{
  class One : Outer()
  class Two : Outer()
  class Three : Outer()
}

fun main(args: Array<String>)
{
  val instance: Outer = Outer.Three()

  val text: String = when (instance)
  {
    is Outer.One -> "One"
    is Outer.Two -> "Two"
    is Outer.Three -> "Three"
  }

  println(text)
}

참고 : 초보자를 위한 Kotlin 200제 라는 책을 기반으로 공부 내용을 정리하였습니다.

확장 함수란 문법은 상속 없이 클래스 외부에서 멤버 함수를 추가할 수 있는 문법을 뜻한다.

아래의 예제에서는 String 클래스에서 isNumber이라는 기존에 정의되어 있지 않은 함수를 확장 함수 문법을 통하여, 추가한 것이다.

fun String.isNumber(): Boolean
{
  var i = 0
  while (i < this.length)
  {
    if (!('0' <= this[i] && this[i] <= '9'))
    return false
    i += 1
  }
  return true
}

fun main(args: Array<String>)
{
  println("1234567890".isNumber())
}

그리고 확장 프로퍼티는 함수가 아닌 Property를 확장하는 것이다.

아래의 예제 코드를 참고하면 되겠다.

val String.isNumber: Boolean
  get()
  {
    var i = 0
    while (i < this.length)
    {
      if (!('0' <= this[i] && this[i] <= '9'))
      return false
      i += 1
    }
    return true
  }

fun main(args: Array<String>)
{
  println("1234567890".isNumber)
}

참고 : 초보자를 위한 Kotlin 200제 라는 책을 기반으로 공부 내용을 정리하였습니다.

'Kotlin' 카테고리의 다른 글

[Kotlin] 함수 리터럴과 람다식, 익명함수, it 식별자  (0) 2020.09.06
[Kotlin] Sealed Class  (0) 2020.09.01
[Kotlin] is 연산자  (0) 2020.09.01
[Kotlin] Nothing type, Nullable, null  (0) 2020.08.31
[Kotlin] Class  (0) 2020.08.29

is 연산자란 java에서 InstanceOf의 키워드와 동일한 역할을 한다.

다시 말하자면, 참조 변수가 실제로 가리키고 있는 객체의 타입을 알아낼 수 있는 역할을 한다.

이에 대한 예제는 다음과 같다.

open class Person(val name: String, val age: Int)

class Student(name: String, age: Int, val id: Int) : Person(name, age)

class Professor(name: String, age: Int) : Person(name, age)

fun main(args: Array<String>)
{
	val person: Person = Student("Mark Zuckerberg", 33, 20171225)
	println(person is Person)
	println(person is Student)
	println(person is Professor)

	val person2: Person = Professor("Kim", 48)
	println(person2 is Person)
	println(person2 is Student)
	println(person2 !is Professor)
}

위의 예제 코드를 확인할 수 있듯이 객체 타입을 비교 하고 있으며, 이에 대한 결과는 다음과 같다.

println(person is Person)  : true

println(person is Student) : true
println(person is Professor) : false

println(person2 is Person) : true
println(person2 is Student) : false
println(person2 !is Professor) : false

 

참고 : 초보자를 위한 Kotlin 200제 라는 책을 기반으로 공부 내용을 정리하였습니다.

'Kotlin' 카테고리의 다른 글

[Kotlin] Sealed Class  (0) 2020.09.01
[Kotlin] 확장함수 / 확장 프로퍼티  (0) 2020.09.01
[Kotlin] Nothing type, Nullable, null  (0) 2020.08.31
[Kotlin] Class  (0) 2020.08.29
[Kotlin] lateinit  (0) 2020.08.29

Nothing Type은 실행 흐름이 도달할 수 없는 구역을 나타내기 위한 특수 타입이라고 생각하면 된다.

다시 이야기 하자면, Nothing 으로 정의된 함수는 Return 처리 하지 않는 함수라는 것을 명시 하는 것이라고 보시면 될 것 같습니다.

예를 들어서, 아래의 예제 코드를 보자

fun throwing(): Nothing = throw Exception()

fun main(args: Array<String>)
{
  val i: Int = throwing()
  println(i)
}

위의 코드에서 보면 "throwing()" 함수 호출 후, Process가 멈추게 된다.

 

그러나 만약 아래와 같이 정의하게 된다면, compile error가 발생하게 된다.

fun test(a:Int, b:Int): Nothing = {return a + b}

fun main(args: Array<String>)
{
	val i: Int = test(1, 30)
	println(i)
}

 

참고 사이트 : https://readystory.tistory.com/143

 

[Kotlin] 헷갈리는 "Nothing" 확실하게 이해하기(feat. Any, Unit)

기존에 자바에 대한 지식이 있는 상태에서 코틀린으로 넘어오신 분들은 코틀린에서 제공하는 대다수의 타입과 클래스들에 대해 거부감이 없으실테지만, 그럼에도 Any와 Unit까지는 어찌어찌 이��

readystory.tistory.com

Nullable Type과 null 에 대해서 알아보자

아래의 Kotlin 코드를 보면,  Nullable type과 null간의 관계를 알 수 있다.

fun main(args: Array<String>)
{
  var testCls: TestClass ? = TestClass()
  testCls = null

  var num: Int? = null
  num = 10
}

위의 코드를 보면, 타입 뒤에 ? 를 붙이는 것을 볼 수 있는데, 이는 해당 타입을 nullable하게 만들 수 있다고 정의 하는 것이다.

다시 말하자면, null값을 지정할 수 있는 변수를 뜻한다.

 

위와 같이 변수에 null 값을 지정하도록 선언할 수 있다고 한다면, 안전한 호출 연산자(?.)를 통하여, null 예외 처리를 할 수 있다.

다음의 예제 코드를 보자

fun main(args: Array<String>)
{
  var obj: Building? = null
  obj?.print()
  obj?.name = "Alice"

  obj = Building()
  obj?.name = "Tower"
  obj?.date = "20200810"
  obj?.area = 131_3212
  obj?.print()
}

위의 코드를 보면, obj에 null을 지정하지만, compile error는 발생하지 않으며, 또한 정상적으로 실행이 된다.

이유는 안전한 호출 연산자(?.)를 호출하였기 때문이다.

안전한 호출 연산자(?.)를 호출하게 되면, 해당 객체가 Null이여도 Exception이 발생하지 않으며, 또한 프로퍼티 또는 참조 함수를 호출하지도 않는다.

 

또한 이 반대도 존재한다.

Not-null 단정 연산자(!!)로 해당 연산자를 선언하게 되면, 해당 객체가 null일시, 반드시 Exception이 발생하게 된다.

fun main(args: Array<String>)
{
  var obj: Building? = Building()
  obj!!.name = "City"
  println(obj!!.name)

  obj = null
  obj!!.print()
}

위의 예제 코드에서는 결국 obj!!.print()에서 Exception이 발생하게 된다.

 

추가적으로 엘비스 연산자(?:)라 하여, 해당 객체가 널이면, 대신 다른 처리를 하도록 지정하는 것도 존재한다.

이는 다음과 같이 생각하면 된다.

[피연산자]?:[Null일 경우 표시할 값]왼쪽의 피 연산자가 null이 아니면, 그 값을 그대로 사용하고, 만약 null일 경우에는 [Null일 경우 표시할 값]으로 대체한다.

 

이에 대한 예제 코드는 다음과 같다.

fun main(args: Array<String>)
{
  val number: Int? = null
  println(number ?: 0)

  val number2: Int? = 15
  println(number2 ?: 0)
}

위의 코드를 실행하면, 결국은 다음과 같은 결과가 나오게 된다.

0

15

 

참고 : 초보자를 위한 Kotlin 200제 라는 책을 기반으로 공부 내용을 정리하였습니다.

'Kotlin' 카테고리의 다른 글

[Kotlin] 확장함수 / 확장 프로퍼티  (0) 2020.09.01
[Kotlin] is 연산자  (0) 2020.09.01
[Kotlin] Class  (0) 2020.08.29
[Kotlin] lateinit  (0) 2020.08.29
[Kotlin] const  (0) 2020.08.29

Class의 생성자와 초기화 블록은 다음과 같이 한번에 초기화 할 수 있으며, 또한 분리할 수도 있다.

fun main(args: Array<String>) {
  val person = Person("Alice", 23)
  println("이름 = ${person.name}")
  println("나이 = ${person.age}")
}

// 초기화를 한군데서 할 경우.
class Person constructor(name:String, age:Int)
{
  val name:String
  val age:Int

  init
  {
    this.name = name
    this.age = age
  }
}

// 초기화를 분리할 경우.
class Person constructor(name:String, age:Int)
{
  val name:String
  val age:Int

  init
  {
  	this.name = name
  }

  init
  {
  	this.age = age
  }
}

또한 위와 같이 class를 초기화 및 선언 할 수 있으나, 다음과 같이 한번에 선언하는 것도 가능하다.

class Person(val name:String, val speed:Int=0)

Class는 다음과 같이 여러가지 보조 생성자를 선언할 수 있다.

class [클래스 이름] constructor(매개변수)

{

    // 보조 생성자 1

    constructor(매개변수):this(인수)

    {

        ...

    }

    // 보조 생성자 2

    constructor(매개변수):this(인수)

    {

        ...

    }

    ...

}

위의 구조를 기반으로 생성된 예제는 다음과 같다.

fun main(args: Array<String>) {
    val person4 = Person4Class()
    println("Name = ${person4.name}")
    println("Age = ${person4.age}")
    println("Zone = ${person4.zone}")

    val person4_1 = Person4Class("csjung", 30)
    println("Name = ${person4_1.name}")
    println("Age = ${person4_1.age}")
    println("Zone = ${person4_1.zone}")

    val person4_2 = Person4Class("csjung", 30, "Seoul")
    println("Name = ${person4_2.name}")
    println("Age = ${person4_2.age}")
    println("Zone = ${person4_2.zone}")
}

class Person4Class {
    var name:String
    var age:Int
    var zone:String

    init {
        this.name = "Empty"
        this.age = 0
        this.zone = "Empty"

        println("Init Block 실행 중 :: ${this.name}, ${this.age}")
    }

    constructor() {
        println("보조 생성자 실행 중 :: ${this.name}, ${this.age}")
    }
    init {
        println("Init Block 실행 중 2 :: ${this.name}, ${this.age}")
    }

    constructor(name:String, age:Int) : this() {
        println("보조 생성자 실행 중 2 :: ${this.name}, ${this.age}")
        this.name = name
        this.age = age
    }

    constructor(name:String, age:Int, zone:String) : this(name, age) {
        println("보조 생성자 실행 중 3 :: ${this.name}, ${this.age}")
        this.zone = zone
    }

    init {
        println("Init Block 3 실행 중 :: ${this.name}, ${this.age}, ${this.zone}")
    }
}

위의 예제에 대한 결과는 다음과 같다.

------------------------------------

Init Block 실행 중 :: Empty, 0

Init Block 실행 중 2 :: Empty, 0

Init Block 3 실행 중 :: Empty, 0, Empty

보조 생성자 실행 중 :: Empty, 0

Name = Empty

Age = 0

Zone = Empty

 

------------------------------------

Init Block 실행 중 :: Empty, 0

Init Block 실행 중 2 :: Empty, 0

Init Block 3 실행 중 :: Empty, 0, Empty

보조 생성자 실행 중 :: Empty, 0

보조 생성자 실행 중 2 :: Empty, 0

Name = csjung

Age = 30

Zone = Empty

 

------------------------------------

Init Block 실행 중 :: Empty, 0

Init Block 실행 중 2 :: Empty, 0

Init Block 3 실행 중 :: Empty, 0, Empty

보조 생성자 실행 중 :: Empty, 0

보조 생성자 실행 중 2 :: Empty, 0

보조 생성자 실행 중 3 :: csjung, 30

Name = csjung

Age = 30

Zone = Seoul

 

위의 예제를 보면, "보조 생성자 실행 중 "이라는 문구 표시가 첫번째는 하나만, 두번째는 2 가지, 세번째는 3가지가 출력된다.

이는 생성자 뒤에 있는 this( ... ) 라는 함수에 따라 어떤 생성자가 호출되는 지를 보여주는 것이다.

예를 들면, 세번째는 this(name, age)는 "constructor(name:String, age:Int) : this()" 생성자를 호출하며, 이는 또한 다시 "constructor()" 생성자를 호출한다.

 

Class에서의 Property에 대한 Getter/Setter 선언 방법은 다음과 같다.

class Person
{
  var age:Int = 0
  get()
  {
    return field
  }

  set(value)
  {
    field = if(value >= 0) value else 0
  }
}

fun main(args: Array<String>) {
  val person = Person()
  person.age = -30
  println(person.age) // Result : 0
}

위와 같이 Getter와 Setter를 정의하게 되면, main함수에서 Property에 값을 설정 및 가져올 때, 해당 정의 내용을 호출하게 된다.

 

또한 Class를 이용하여, 연산자 오버로딩을 할 수 있다.

Kotlin에서는 다음과 같이 함수 이름을 사용하고 있다.

단항 연산자

+a : unaryPlus

-a : unaryMinus

!a : not

 

이항 연산자

+ : plus

- : minus

* : times

/ : div

% : rem

+= : plusAssign

-= : minusAssign

*= : timesAssign

/= : divAssign

%= : remAssign

비교 연산자

>, <, >=, <= : compareTo

==, != : equals

이를 이용한 예제 코드는 다음과 같다.

class Coordinate(var x:Int = 0, var y:Int = 0)
{
  operator fun plus(other:Coordinate):Coordinate
  {
  	return Coordinate(x + other.x, y + other.y)
  }

  operator fun minus(other:Coordinate):Coordinate
  {
  	return Coordinate(x - other.x, y - other.y)
  }

  operator fun times(other:Coordinate):Coordinate
  {
  	return Coordinate(x * other.x, y * other.y)
  }

  operator fun div(other:Coordinate):Coordinate
  {
  	return Coordinate(x / other.x, y / other.y)
  }

  fun print()
  {
  	println("x:$x, y:$y")
  }
}

fun main(args: Array<String>) {
  val coorA = Coordinate(10, 20)
  val coorB = Coordinate(20, 20)
  var coorPlus = coorA + coorB
  var coorMinus = coorA - coorB
  var coorTiems = coorA * coorB
  var coorDiv = coorA / coorB

  coorPlus.print() // Result : x:30, y:40
  coorMinus.print() // Result : x:-10, y:0
  coorTiems.print() // Result : x:200, y:400
  coorDiv.print() // Result : x:0, y:1
}

Class 의 Property를 Index 로 접근할 수 있다.

이를 Indexed Access Operator라고 한다.

Property의 get/set을 다음의 예제와 같이 구현 하면 된다.

class Person(var name:String, var birthday:String)
{
  operator fun get(position:Int):String
  {
    return when(position) {
      0 -> name
      1 -> birthday
      else -> "unknown"
    }
  }

  operator fun set(position:Int, value:String)
  {
    when(position) {
      0 -> name = value
      1 -> birthday = value
    }
  }
}

fun main(args: Array<String>) {
  val person = Person("Kotlin", "2020-08-20")
  println(person[0]) // Result : Kotlin
  println(person[1]) // Result : 2020-08-20
  println(person[-1]) // unknown

  person[0] = "Java"
  println(person.name) // Java
}

위에서 보시는 것 과 같이 "position" 0을 name으로 1을 birthday로 정의 하면, person[0] 은 name으로 처리되고, person[1]은 birthday로 처리하게 된다.

 

invoke 연산자는 함수 이름 없이 호출할 수 있다.

다음의 예제 코드를 참고하길 바란다.

class MyFunction(val id:Int, val name:String)
{
  operator fun invoke(value:Int)
  {
    println(value)
    println("id:$id\nname:$name")
  }
}

위와 같이 정의 하게 된다면, 다음과 같이 함수 이름없이 사용이 가능하다.

val myFun = MyFunction(1234567, "Invoke Operator Test Code")
myFun(108)

중위 표기법에 대한 사용 법

구성 : 피연산자 + 연산자 + 피연산자

구성 방법 : 멤버 함수의 매개 변수가 하나뿐이면 함수 호출을 중위 표기법으로 표기할 수 있다.

정의 방법 : 중위 표기법으로 정의할 시, 멤버 함수 선언문 앞(fun)에 infix 를 붙여야 한다.

예제는 다음과 같다.

class InfixTestClass(var x:Int = 0, var y:Int = 0) {
  infix fun from (base:InfixTestClass) : InfixTestClass
  {
      return InfixTestClass(x - base.x, y - base.y)
  }
}

fun main(args:Array<String>)
{
  val infixTestCls = InfixTestClass(3, 6) from InfixTestClass(1, 1)
  println("Infix test =============================== ")
  println(infixTestCls.x)
  println(infixTestCls.y)
  println("========================================== ")
}

Class 상속에 대한 사용 법

상속하기 위한 부모 Class에 대해서는 open이라는 키워드로 정의 하여야 한다.

그리고 상속 되는 Class에서는 ":" 이후에 부모 클래스를 정의 하면 된다.

이에 대한 사용 법은 다음과 같다.

open class InheritancePerson(val name:String, val age:Int)

class InheritanceStudent(name:String, age:Int, val id:Int) : InheritancePerson(name, age)

Class에 대한 상속은 위와 같이 한다면, 함수 오버라이딩은 다음과 같이 부모 클래스의 함수에 open 키워드로 정의 한 후, 자식 클래스에 존재하는 동일 명칭의 함수에 override 키워드를 사용하면 된다.

사용 법은 다음과 같다.

open class AAA
{
  open fun func() = println("AAA")
}

class BBB : AAA()
{
  override fun func()
  {
    super.func()
    println("BBB")
  }
}

fun main(args: Array<String>)
{
  AAA().func()
  BBB().func()
}

위의 코드에 대한 결과물을 보면 다음과 같은 결과물이 돌출된다.

Result

-----------------

AAA

AAA

BBB

 

만약 멤버 함수의 재 오버라이딩을 막고 싶다면, 다음과 같이 final을 붙여주면 된다.

open class AAA
{
  open fun func() = println("AAA")
}

open class BBB : AAA()
{
  final override fun func()
  {
    super.func()
    println("BBB")
  }
}

open class CCC : BBB()
{
  override fun func() <-- 에러 발생.
  {
  }
}

위에서 CCC는 빌드 에러가 발생하게 된다.

프로퍼티 또한 멤버함수와 같이 오버라이딩을 할 수 있다.

사용법은 위와 같으며, 이에 대한 사용 방법은 다음의 예제 코드를 참고하여, 이해하길 바란다.

open class AAA
{
  open var number = 10
    get()
    {
      println("AAA number Getter 호출됨")
      return field
    }
    set(value)
    {
      println("AAA number Setter 호출됨")
      field = value
    }
}

class BBB : AAA()
{
override var number: Int
  get()
  {
    println("BBB number Getter 호출됨")
    return super.number
  }
  set(value)
  {
    println("BBB number Setter 호출됨")
    super.number = value
  }
}

fun main(args: Array<String>)
{
  val test = BBB()
  test.number = 5
  test.number
}

이에 대한 결과물은 다음과 같다.

Result

-----------------

BBB number Setter 호출됨

AAA number Setter 호출됨

BBB number Getter 호출됨

AAA number Getter 호출됨

 

접근 지정자에 대해서 알아보겠다.

보통 C/C++/Java등에서는 Class 별로 접근 권한을 지정할 수 있다.

대표적으로 public / protected / private 라는 키워드를 사용한다.

그러나 Kotlin에서는 internal 이라는 새로운 키워드가 존재한다. 

이는 해당 Project 내에서는 모두 접근이 가능하도록 한다는 권한을 뜻하는 것이며, 또한 IntelliJ Project 에서만 사용 가능한 것으로 알고 있다.

 

추상 클래스 및 Interface를 생성할 경우, java와 동일하게 abstract 키워드를 사용하여, 정의 하면 된다.

사용 방법에 예는 다음과 같다.

// ---------------------- 추상 클래스
abstract class Person
{
	abstract fun getSalary(): Int
}

class Student(private val tuition: Int) : Person()
{
	override fun getSalary() = -tuition
}

class Professor(private val classCount: Int) : Person()
{
	override fun getSalary() = classCount * 200
}

// --------------------- Interface
interface Printable
{
	fun print(): Unit
}

class AAA : Printable
{
	override fun print()
	{
		println("Hello")
	}
}

Kotlin에서는 내부 클래스를 선언할 때에는 inner 키워드를 사용하여, 정의 한다.

그리고 내부 클래스에서 외부 클래스의 변수 및 함수를 접근하고자 할 경우, "this@{Out Class 이름}을 표기하여야 한다.

사용 하는 방법에 대한 예는 다음과 같다.

class Outer(private val value: Int)
{
	fun print()
	{
		println(this.value)
	}

	inner class Inner(private val innerValue: Int)
	{
		fun print()
		{
			this@Outer.print()
			println(this.innerValue + this@Outer.value)
		}
	}
}

fun main(args: Array<String>)
{
	val instance: Outer = Outer(610)
	val innerInstance: Outer.Inner = instance.Inner(40)
	innerInstance.print()
}

Kotlin에서는 Data에 특화된 class가 존재한다. 이를 데이터 클래스라고 한다.

해당 class를 선언할 시, data 라는 키워드를 정의 하여야 한다.

또한 data class를 선언할 시, 다음과 같이 함수들이 오버라이딩 된다.

1. equals, hashCode, toString 멤버 함수가 자동으로 오버라이딩 된다.

2. equals 멤버 함수는 각 프로퍼티의 값이 모두 같으면 true로 처리되며, 만약 하나라도 다를 시에는 false로 표기하도록 오버라이딩 된다.

3. toString 멤버 함수는 class명(프로퍼티명=값, ...) 형태로 문자열로 표기 되도록 오버라이딩 된다.

 

또한 데이터 클래스에 한하여, 여러개의 변수로 쪼개는 것이 가능하다.

이에 대한 예제는 다음과 같다.

data class Employee(val name: String, val age: Int, val salary: Int)

fun main(args: Array<String>)
{
	val first = Employee("John", 30, 3000)
	val second = Employee("Page", 24, 5300)
	val third = first.copy()
	val first_2 = Employee("John", 30, 3000)

	println(first.toString())
	println(third.toString())
	println(first == second)
	println(first == third)
	println(first == first_2)
    
    // ---------- Data class 쪼개는 방법
    val (name, _, salary) = Employee("John", 30, 3300)
	println(name)
	println(salary)
}

(위의 예제에서 보시면, _ 이 있는데, 이를 선언하게 되면, 해당 변수의 값 을 무시할 수 있다.

 

참고 : 초보자를 위한 Kotlin 200제 라는 책을 기반으로 공부 내용을 정리하였습니다.

'Kotlin' 카테고리의 다른 글

[Kotlin] is 연산자  (0) 2020.09.01
[Kotlin] Nothing type, Nullable, null  (0) 2020.08.31
[Kotlin] lateinit  (0) 2020.08.29
[Kotlin] const  (0) 2020.08.29
[Kotlin] inline 함수  (0) 2020.08.29

class 의 property 는 반드시 초기화를 해주어야 한다.

그러나 class안에 기존에 정의된 class를 property를 추가할 경우에는 초기화가 어렵다.

이를 해결하기 위하여, 추가된 키워드라 보면 될 것으로 보인다.

 

해당 내용에 대한 예제는 다음과 같다.

// 점을 표현하는 클래스
class Point(val x: Int, val y: Int)

// 사각형을 표현하는 클래스
class Rect
{
  lateinit var pt: Point
  lateinit var pt2: Point

  val width: Int
  	get() = pt2.x - pt.x
  val height: Int
  	get() = pt2.y - pt.y
  val area
  	get() = width * height
}

fun main(args: Array<String>)
{
  val rect = Rect()
  rect.pt = Point(3, 3)
  rect.pt2 = Point(6, 5)

  println("너비: ${rect.width}")
  println("높이: ${rect.height}")
  println("넓이: ${rect.area}")
}

예제를 보면 확인할 수 있듯이, Rect Class안에 pt, pt2 라는 Point Property를 추가하였으며, 또한 main 함수에서 pt, pt2 를 초기화 하는 것을 확인 할 수 있다.

lateinit 키워드는 이러한 역할을 하기 위함이라고 보면 될 것으로 판단된다.

 

참고 : 초보자를 위한 Kotlin 200제 라는 책을 기반으로 공부 내용을 정리하였습니다.

'Kotlin' 카테고리의 다른 글

[Kotlin] Nothing type, Nullable, null  (0) 2020.08.31
[Kotlin] Class  (0) 2020.08.29
[Kotlin] const  (0) 2020.08.29
[Kotlin] inline 함수  (0) 2020.08.29
[Kotlin] 객체 선언 및 동반자 객체  (0) 2020.08.29

+ Recent posts