fun main() {
for (i in 1..10) {
if (i == 3) break
println(i) // 1, 2 출력
}
}
fun main() {
for (i in 1..10) {
if (i == 3) continue
println(i) // 3을 제외한 모든 숫자 출력
}
}
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 일 때 까지만 출력됨
}
}
}
타 언어와 동일!
사람의 이름과 출생년도를 관리하는 클래스를 만들어보자.
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}입니다.")
}
}
7장에서 클래스를 정의할 때 생성자를 이미 선언했다.
생성자는 인스턴스의 속성을 초기화하고, 인스턴스 생성시 필요한 구문을 수행한다.
타 언어의 init을 말함
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}님이 생성되었습니다.")
}
}
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("보조 생성자가 사용되었습니다.")
}
}
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}살 입니다.")
}
}
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, "개")
와 같이 상속할 클래스를 적어주면 된다.
(타입은 "개"로 고정한 것)
*지나친 상속구조는 코드를 어렵게 만든다
참고하기
코틀린 기초 문법) 15. 코틀린 추상 클래스 및 인터페이스
기본적으로 수퍼클래스와 서브클래스에 동일한 이름의 함수를 만들 수 없다. 하지만 수퍼클래스에서 허용만 한다면 오버라이딩이라고 하여 같은 이름과 형태로 된 함수의 내용을 구현할 수 있다.
fun main() {
var t = Tiger()
t.eat() // "고기를 먹습니다" 출력
}
open class Animal {
open fun eat() {
println("음식을 먹습니다")
}
}
class Tiger : Animal() { // Animal을 상속받음
override fun eat() {
println("고기를 먹습니다")
}
}
수퍼클래스에서 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("당근을 먹습니다")
}
}
추상클래스는 일부 함수가 미구현 되어 있어 직접 인스턴스를 만들 수는 없고, 서브클래스에서 오버라이드를 하여 함수를 채워준 후에 해당 서브클래스로 인스턴스를 만들어야 한다.
자바에서는 추상클래스와 인터페이스의 차이를 추상함수로만 구성되어 있느냐(인터페이스), 그렇지 않으냐(추상클래스)로 구분한다고 들었다.
하지만 코틀린에서는 추상클래스와 인터페이스 모두 추상함수와 일반함수, 속성을 가질 수 있다. 다만 추상클래스는 생성자를 가질 수 있는 반면 인터페이스는 생성자를 가질 수 없다.
인터페이스에서 구현부가 있는 함수는 open 함수로 간주하고, 구현부가 없는 함수는 abstract 함수로 간주한다. 별도의 키워드 없이 인터페이스에 포함된 모든 함수를 서브클래스에서 재정의가 가능하며, 하나의 서브 클래스에서 한 번에 여러 개의 인터페이스를 상속받을 수 있다.
정리(kotlin)
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("허겁지겁 뜁니다")
}
}