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

const 같은 경우에는 inline 키워드와 동일한 역활을 한다.

단지, const 키워드는 inline과는 다르게 변수에만 사용 가능하다.

 

const 사용에 대한 간단한 예는 다음과 같다.

const val hello = "Hello" + " World!"

object Foo
{
  const val bar = "bar"
}

fun main(args: Array<String>)
{
  println(hello)
  println(Foo.bar)
}

위의 예제와 같이 선언하면, 결국 컴파일 시, 하기와 같이 변경된다.

fun main(args: Array<String>)
{
  println("Hello World!")
  println("bar")
  println("Hello World!")
  println("bar")
}

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

'Kotlin' 카테고리의 다른 글

[Kotlin] Class  (0) 2020.08.29
[Kotlin] lateinit  (0) 2020.08.29
[Kotlin] inline 함수  (0) 2020.08.29
[Kotlin] 객체 선언 및 동반자 객체  (0) 2020.08.29
[Kotlin] 기초 - 함수  (0) 2020.08.27

inline 함수는 C의 전처리기에서 define과 같은 역확을 한다.

다음의 예제를 보고 설명하겠다.

inline fun hello()
{
  println("Hello")
  println("Kotlin")
}

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

위와 같이 inline 키워드를 사용하여, 함수를 선언해 놓으면, 컴파일 후에는 결국은 다음과 같이 변경된다.

fun main(args: Array<String>)
{
  println("Hello")
  println("Kotlin")
  println("Hello")
  println("Kotlin")
  println("Hello")
  println("Kotlin")
}

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

'Kotlin' 카테고리의 다른 글

[Kotlin] lateinit  (0) 2020.08.29
[Kotlin] const  (0) 2020.08.29
[Kotlin] 객체 선언 및 동반자 객체  (0) 2020.08.29
[Kotlin] 기초 - 함수  (0) 2020.08.27
[Kotlin] 기초 - typealias, 제어문  (0) 2020.08.27

Kotlin에서는 하기와 같이 객체를 선언 할 수 있다.

object TestObject
{
  var tempStr: String = ""
  var tempInt: Int = 0
  fun print()
  {
    println(tempStr)
    println(tempInt)
  }
}

fun main(args: Array<String>)
{
  // 식별자 Person으로 객체에 바로 접근 가능
  TestObject.tempStr = "Test Object"
  TestObject.tempInt = 100
  TestObject.print()
}

위의 예제와 같이 new로 생성하지 않고, java의 singletone을 사용하는 것과 같이 사용 할 수 있다.

 

동반자 객체는 클래스 안에 포함되는 이름 없는 객체를 뜻한다.

다시 말하면, kotlin에서는 static 키워드가 존재하지 않는다. 하지만 동반자 객체를 이용하면, class내에서 java의 static 과 같은 함수를 만들 수 있다.

예를 들면 다음과 같다.

class TestClass private constructor()
{
  companion object
  {
    fun create(): TestClass
    {
      countCreated += 1
      return TestClass()
    }

    var countCreated = 0
    private set
  }
}

fun main(args: Array<String>)
{
  val a = TestClass.create()
  val b = TestClass.create()
  println(TestClass.countCreated)
}

자세한 설명은 하기의 블로그를 참고하면 더욱 도움이 된다.

참조 사이트 : https://medium.com/@lunay0ung/kotlin-object-declaration-%EA%B7%B8%EB%A6%AC%EA%B3%A0-companion-object-feat-static-d5c97c21168

 

Kotlin: Object Declaration, 그리고 Companion Object (feat.static)

먼저, Object(객체)란 무엇일까?

medium.com

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

'Kotlin' 카테고리의 다른 글

[Kotlin] const  (0) 2020.08.29
[Kotlin] inline 함수  (0) 2020.08.29
[Kotlin] 기초 - 함수  (0) 2020.08.27
[Kotlin] 기초 - typealias, 제어문  (0) 2020.08.27
[Kotlin] 기초 - 정수/실수/문자 타입과 문자열  (0) 2020.08.27

Kotlin에서는 다음과 같은 방식으로 함수를 선언한다.

fun {식별자}({인자}:{type} ...):{반환타입}

{

}

 

또한 함수 선언을 간략화 할 수 있다.

fun {식별자}({인자}:{type} ...):{반환타입} = ...

 

fun function(a:Double):Double
{
    return 3.0 + 7 + a
}

// 함수 선언 간략화
fun function(a:Double):Double = 3.0 + 7 + a
fun function(a:Double) = 3.0 + 7 + a

Unit type은 Java나 C에서 사용하는 문법 중 void와 같은 역활을 한다.

fun myFunction(a:Int, b:Int):Unit
{
    println("a: " + a + ", b: " + b)
}

// return type 을 생략 가능
fun myFunction(a:Int, b:Int)
{
    println("a: " + a + ", b: " + b)
}

// 함수를 다음과 같이 간략화도 가능
fun myFunction(a:Int, b:Int) = println("a: " + a + ", b: " + b)

Default 인수를 C/C++과 같이 초기 값을 선언할 수 있다.

그리고 함수를 실질적으로 사용할 시, 값만 선언하여 사용할 수 있으나, 파라메터 이름을 이용하여, 값을 설정할 수 있다.

예제는 다음과 같다.

funDefaultTest(89, 96)
funDefaultTest(89, 96, true)
funDefaultTest(90)
funDefaultTest(66, print = true)
funDefaultTest(print = true)
funDefaultTest(print = true, a = 10, b = 23)

// 함수 인자 값 초기과
fun funDefaultTest(a:Int = 0, b:Int = 0, print:Boolean = false) : Double
{
    var result = (a + b) / 2.0
    if(print)
    	println(result)
    return result
}

N개의 인수를 받는 함수를 선언할 수 있다. (가변 인수)

사용 방법은 vararg라는 키워드를 사용하여, 가능하다.

또한 가변 인수에 대해서 선언하지 않는다고 하더라도 가변 인수의 size 값이 0으로 받아오기 때문에 정상적으로 처리할 수 있다.

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

fun main(args: Array<String>) {
  testVarargFun(1,2,3,4,5,6,7)
  testVarargFun(32, 57,12)
  testVarargFun()
}

fun testVarargFun(vararg numbers:Int) : Int
{
  var count:Int = numbers.size
  var i:Int = 0; var sum:Int = 0

  while(i < count)
  {
    sum += numbers[i]
    i++
  }

  return sum
}

// 가변 인수는 일반 인수와 같이 병행하여 사용이 가능
fun testVarargFun(something:Char, vararg numbers:Int) : Int
fun testVarargFun(vararg numbers:Int, something:Char) : Int

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

typealias 키워드를 이용하여, C와 C++ 언어의 typedef와 같이 type에 별명을 붙일 수 있다.

typealias csjungNumber = Int

fun main(args: Array<String>) {
    var a:csjungNumber = 10
    println(a)
}

if - else 문 같은 경우에는 다른 언어들과 동일하게 사용하고 있으며, Kotlin에서는 추가적으로 표현식에도 사용할 수 있다.

al value:Int = if(10 > 5) {
println("10은 5보다 크다.")
10
} else {
println("10은 5보다 크지 않다.")
5
}

when 문은 타 언어에서 switch문과 같은 역할을 한다.

when ({타깃 표현식}) {

    {타깃 표현식과 비교할 값} ->

        {

            ....

        }

}

// 일반적인 사용법
when(score / 10)
{
  6 -> {
	println("D")
  }

  7 -> {
  	println("C")
  }

  8 -> {
  	println("B")
  }

  9, 10 -> {
  	println("A")
  }

  else -> {
  	println("F")
  }
}

// 표현식으로 사용법
val grade: Char = when(score / 10)
{
  6 -> 'D'
  7 -> 'C'
  8 -> 'B'
  9, 10 -> 'A'
  else -> 'F'
}

while문 같은 경우에는 타 언어와 동일한 방식으로 사용되고 있다.

do {
  i += 1
  if(i >= 5) {
    ...
    break
  } else if(i == 2) {
    ...
    continue
  }
  ...
} while(true)

Label 은 중첩된 반복문의 흐름을 제어하기 위한 키워드 이다.

사용 방법은 다음과 같다.

- while 구문

{label name}@ while 구문

- break 구문

 break@{label name}

Label에 대한 사용 예제는 다음과 같다.

fun main(args: Array<String>) {
  var x = 0;
  var y = 0;
  var z = 0;

  outer@ while(x <= 20) {
    y = 0
    while(y <= 20) {
      z = 0
      while(z <= 20) {
        if(x+y+z == 15 && x - y - z == 5) {
            break@outer
        }
        z++
      }
      y++
    }
    x++
  }

  println("x:$x, y:$y, z:$z")
}

위의 예제를 보았을 때, "if(x+y+z == 15 && x - y - z == 5)" 라는 조건에 참이 된다면, "while(z <= 20)"의 흐름을 계속 타지 않고, "outer@while(x <= 20)" 의 흐름을 바로 탈출하게 된다.

 

만약 outer@ 가 "while(y <= 20)" 에 존재한다면, 해당 코드는 while(x <= 20) 의 흐름을 계속 타고 있을 것이다.

 

위의 label에 대한 예제 코드의 결과물은 다음과 같다.

결과 값

x:10, y:0, z:5

 

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

Kotlin에서 각 타입 및 크기는 다음과 같다.

 

정수 타입

- Byte      |        1 byte

- Short    |        2 byte

- Int         |        4 byte

- Long     |        8 byte

 

실수 타입

- Float     |        4 byte

- Double  |        8 byte

 

문자 타입

- Char    |      1 byte

 

문자열

- String

 

각 타입 별로 값을 정의 할 경우, "_" 를 이용하여, 숫자들의 자리를 구분할 수 있다. 이는 위치 및 갯수에 제약이 없다.

(하기의 예제 참고)

val a:Byte = 125
val b:Short = (100 + 200) * 100
var c:Int = 12_4354_6538	// 숫자 안에 _ 를 넣어주면, 숫자를 좀더 알아보기 쉽게 정의할 수 있다.
// _ 의 위치와 갯수는 마음대로 넣을 수 있으며, 실수 타입에서도 적용 가능.
var d:Int = 1243546538

c = 0xFF_88_88	// 0x로 시작하면, 16진수로 인식
c = 0b01010010_01100011_01110101_01000101 //0b로 시작하면, 2진수로 인식
var e:Long = -543_7847_3984_7238_4723

var f:Float = 67.6f
val g:Double = 658.456

f = (f+g).toFloat()

var ch:Char = 'A'
ch = '\uAC00' //<-- /u를 이용하여, Unicode를 직접 입력할 수 있다.
ch = '한'

var str:String = "Hello"
str = str+"\nKotlin!"

Kotlin에서는 Int Type보다 작은 정소들을 이용하여, 연산할 시, 반드시 Int로 전환이 되어 결과 값이 발생된다.

예) Byte + Byte = Int, Byte + Short = Int, Byte - Byte = Int, Byte * Short = Int,  Byte / Short = Int

 

※ Kotlin은 8진법을 지원하지 않는다.

 

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

+ Recent posts