Kotlin 기본2

Seongho·2021년 10월 16일
0

Kotlin

목록 보기
2/6

6. 흐름제어와 논리연산자

6.1 흐름제어

  • return - 함수를 종료하고 값을 반환
  • break - 반복문 종료 및 다음 구문으로 넘어가기
    fun main() {
    	for (i in 1..10) {
    		if (i == 3) break
    		println(i) // 1, 2 출력
    	}
    }
  • continue - 다음 반복으로 넘어가기
    fun main() {
    	for (i in 1..10) {
    		if (i == 3) continue
    		println(i) // 3을 제외한 모든 숫자 출력
    	}
    }
  • 코틀린 특! 다중 반복문에서 break, continue를 사용할 때 한 번의 사용으로 여러 반복문을 빠져나오는 등의 동작을 할 수 있다! 기존의 다른 언어와 같은 방법을 사용한다면 아래와 같다.
    fun main() {
    	for (i in 1..10) {
    		for (j in 1..10) {
    			if (i == 1 && j == 2) break // i가 1이고 j가 2일 때 모든 반복문을 끝내고자 한다.
    				println(i)
    		}
    		if (i == 1) break
    		
    	}
    }
    코틀린에서는 loop@ ~ @loop를 사용하여 추가적인 코드 필요 없이 다중 반복문을 끝낼 수 있다.
    fun main() {
    	loop@for (i in 1..10) {
    		for (j in 1..10) {
    			if (i == 1 && j == 2) break@loop // i가 1이고 j가 2일 때 모든 반복문을 끝내고자 한다.
    			println("i: $i, j: $j") // i = 1, j = 1 일 때 까지만 출력됨
    		}
    	}
    }

6.2 논리연산자

  • &&
  • ||
  • !

타 언어와 동일!

7. 클래스의 기본 구조

7.1 클래스의 특징

  • 우리가 다뤘던 자료형(Byte, Short, Int, ...)들도 코틀린 내부에서 클래스로 존재한다.
  • 클래스는 고유의 특징값을 갖는 "속성"과 기능을 구현하는 "함수"로 이루어져 있다.
  • 클래스는 인스턴스를 만들어내는 틀임을 명심하자.

사람의 이름과 출생년도를 관리하는 클래스를 만들어보자.

fun main() {

	var a = Person("박보영", 1990) // 인스턴스 생성
	var b = Person("전정국", 1997)
	var c = Person("장원영", 2004)
	println("안녕하세요, ${a.birthYear}년생 ${a.name}입니다.") // 이렇게 속성을 사용 가능
}

class Person(var name:String, val birthYear:Int) // 함수 없이 속성만 갖는 클래스

클래스에 자기소개하는 함수를 추가하면,

fun main() {

	var a = Person("박보영", 1990) // 인스턴스 생성
	var b = Person("전정국", 1997)
	var c = Person("장원영", 2004)
	a.introduce()
	b.introduce()
	c.introduce()
}

// 함수를 갖는 클래스
class Person(var name:String, val birthYear:Int){
	fun introduce() {
		println("안녕하세요, ${birthYear}년생 ${name}입니다.")
	}
} 

8. 클래스의 생성자

7장에서 클래스를 정의할 때 생성자를 이미 선언했다.

생성자는 인스턴스의 속성을 초기화하고, 인스턴스 생성시 필요한 구문을 수행한다.

타 언어의 init을 말함

8.1 기본 생성자

fun main() {
	var a = Person("박보영", 1990)
	var b = Person("전정국", 1997)
	var c = Person("장원영", 2004)
}

class Person (var name:String, val birthYear:Int) {
	init {
		println("${this.birthYear}년생 ${this.name}님이 생성되었습니다.")
	}
}

8.2 보조 생성자

init으로 선언한 값의 초기값을 지정하고 싶을 때

fun main() {
	var a = Person("박보영", 1990)
	var b = Person("전정국", 1997)
	var c = Person("장원영", 2004)
	var d = Person("이루다") // 보조 생성자가 사용되고, 년도는 1997로 고정
	var e = Person("차은우")
	var f = Person("류수정")
}

class Person (var name:String, val birthYear:Int) {
	init {
		println("${this.birthYear}년생 ${this.name}님이 생성되었습니다.")
	}
	constructor(name:String): this(name, 1997) { // 
		println("보조 생성자가 사용되었습니다.")
	}
}

9. 클래스의 상속

9.1 상속

  • 이미 존재하는 클래스를 확장하여 새로운 속성이나 함수를 추가한 클래스를 만들어야 할 때
  • 여러 개의 클래스를 만들었는데 클래스의 공통점을 뽑아 코드 관리를 편하게 해야 할 때
  • 클래스를 물려주는 쪽이 수퍼 클래스
  • 물려받는 쪽이 서브 클래스
  • 코틀린은 기본적으로 클래스 상속이 막혀있고, 따로 조치를 해줘야 가능하다. (open)

9.2 예시

fun main() {
    println("Hello, world!!!")
}

class Animal (var name:String, var age: Int, var type: String)
{
    fun introduce() {
        println("저는 ${type} ${name}이고, ${age}살 입니다.")
    }
}

Animal을 상속할 수 있도록 하려면

fun main() {
    println("Hello, world!!!")
}

open class Animal (var name:String, var age: Int, var type: String)
{
    fun introduce() {
        println("저는 ${type} ${name}이고, ${age}살 입니다.")
    }
}

9.3 상속의 두 가지 규칙

1) 서브 클래스는 수퍼 클래스에 존재하는 속성과 같은 이름의 속성을 가질 수 없음

2) 서브 클래스가 생성될 때는 반드시 수퍼 클래스의 생성자까지 호출해야 한다.

fun main() {
    var a = Animal("별이", 5, "개")
    var b = Dog("별이", 5)
    a.introduce()
    b.introduce()
    b.bark()
}

open class Animal (var name:String, var age:Int, var type:String)
{
    fun introduce() {
        println("저는 ${type} ${name}이고, ${age}살 입니다.")
    }
}

class Dog (name:String, age:Int): Animal(name, age, "개")
{
	fun bark() {
		println("멍멍")
	}
}

class Cat (name:String, age:Int) : Animal (name, age, "고양이")
{
	fun meow() {
		println("meow")
	}
}

서브 클래스 Dog를 생성할 때 name, age에 var을 붙이지 않았다. 이는 Dog에 자체 속성 이름으로 name, age를 만들어주면 Animal과 겹치기 때문이다. 대신에 일반 parameter로 받아서 Animal 클래스에 직접 넘겨주는 개념이다.

상속은 Dog 클래스 뒤에 :Animal(name, age, "개") 와 같이 상속할 클래스를 적어주면 된다.

(타입은 "개"로 고정한 것)

*지나친 상속구조는 코드를 어렵게 만든다

10. 오버라이딩과 추상화(중요 Java 개념)

참고하기

코틀린 기초 문법) 15. 코틀린 추상 클래스 및 인터페이스

10.1 오버라이딩

기본적으로 수퍼클래스와 서브클래스에 동일한 이름의 함수를 만들 수 없다. 하지만 수퍼클래스에서 허용만 한다면 오버라이딩이라고 하여 같은 이름과 형태로 된 함수의 내용을 구현할 수 있다.

fun main() {
    var t = Tiger()
    t.eat() // "고기를 먹습니다" 출력
}

open class Animal {
    open fun eat() {
        println("음식을 먹습니다")
    }
}

class Tiger : Animal() { // Animal을 상속받음
    override fun eat() {
        println("고기를 먹습니다")
    }
}

10.2 추상화(추상클래스)

수퍼클래스에서 Animal에서는 함수의 구체적인 구현이 없고, 대신 서브클래스에서 eat이라는 함수를 반드시 있어야 한다는 점을 명시하여, 각 서브클래스가 비어있는 함수의 내용을 구현하도록 한다.

추상함수 + 추상클래스

fun main() {
    var r = Rabbit()
    r.eat()
    r.sniff()
}

abstract class Animal {
    abstract fun eat()
    fun sniff() {
        println("킁킁")
    }
}

class Rabbit : Animal() {
    override fun eat() {
        println("당근을 먹습니다")
    }
}

추상클래스는 일부 함수가 미구현 되어 있어 직접 인스턴스를 만들 수는 없고, 서브클래스에서 오버라이드를 하여 함수를 채워준 후에 해당 서브클래스로 인스턴스를 만들어야 한다.

10.3 인터페이스

자바에서는 추상클래스와 인터페이스의 차이를 추상함수로만 구성되어 있느냐(인터페이스), 그렇지 않으냐(추상클래스)로 구분한다고 들었다.

하지만 코틀린에서는 추상클래스와 인터페이스 모두 추상함수와 일반함수, 속성을 가질 수 있다. 다만 추상클래스는 생성자를 가질 수 있는 반면 인터페이스는 생성자를 가질 수 없다.

인터페이스에서 구현부가 있는 함수는 open 함수로 간주하고, 구현부가 없는 함수는 abstract 함수로 간주한다. 별도의 키워드 없이 인터페이스에 포함된 모든 함수를 서브클래스에서 재정의가 가능하며, 하나의 서브 클래스에서 한 번에 여러 개의 인터페이스를 상속받을 수 있다.

정리(kotlin)

  • 추상클래스 - 속성, 추상함수와 일반함수로 구성, 생성자를 가질 수 있다. 추상함수에는 abstract를 붙여야 한다.
  • 인터페이스 - 속성, 추상함수와 일반함수로 구성, 생성자를 가질 수 없다. abstract나 open 등을 따로 붙일 필요 없이, 구현을 해 놨으면 open, 하지 않았으면 abstract로 간주한다.
fun main() {
    var d = Dog()
    println(d.x) // 10
		d.run() // 우다다다 뜁니다
    d.eat() // 허겁지겁 뜁니다
}

interface Runner { // 생성자가 없음 => 그래서 interface() {} 이런 식으로 쓰지 않음
    var x: Int // 속성 선언 가능, 초기화는 불가능, subclass에서 해줘야 한다
    fun run() // abstract로 간주
}

interface Eater {
fun eat() { // open으로 간주
        println("음식을 먹습니다.")
    }
}
class Dog: Runner, Eater {
    override var x: Int = 10
    override fun run() {
        println("우다다다 뜁니다")
    }
    override fun eat() {
        println("허겁지겁 뜁니다")
    }
}

0개의 댓글