2024-06-21

This commit is contained in:
2024-06-21 15:01:25 +09:00
commit b5f6bbb1e0
41 changed files with 1895 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
# 접근 한정자
- private
- protected
- internal
- public
아무런 한정자도 명시하지 않은 경우, 기본 값은 `public`입니다.

287
Writerside/topics/Class.md Normal file
View File

@@ -0,0 +1,287 @@
# 객체
다음과 같이 클래스를 선언합니다.
```kotlin
class Shape {
// ...
}
```
바디가 없는 클래스도 있습니다.
```kotlin
class Empty
```
## 생성자
### 기본 생성자
기본 생성자는 `constructor`를 사용해서 클래스 헤더 부분에 정의합니다.
```kotlin
class Person constructor(name: String) {
// ...
}
```
기본 생성자에 별다른 어노테이션이나 접근한정자를 명시할 필요가 없는 경우에는 `constructor` 키워드를 생략할 수 있습니다.
```kotlin
class Person (name: String) {
// ...
}
class Person public constructor(name: String) {
// ...
}
```
기본 생성자의 경우, 별도의 초기화 로직을 정의할 수 없는 대신, 초기화 블록을 사용할 수 있습니다. 초기화 블록은 `init`을 사용해서 정의하며, 여러 개의 초기화 블록이 있을 경우, 순서대로 실행됩니다. 기본 생성자에 선언된 매개 변수는 초기화 블록에서 사용할 수 있습니다.
```kotlin
class Person (name: String) {
init {
// initializer block ...
}
}
```
### 보조 생성자
두 번째 생성자부터는 클래스 바디에 정의합니다. 기본 생성자가 정의되어 있는 경우에는 기본 생성자로부터 또는 다른 보조 생성자로부터 값을 위임 받아야 합니다.
기본 생성자가 없는 경우라도, 암묵적으로 위임 처리가 진행되며 초기화 블록도 실행됩니다.
```kotlin
class Person (name: String) {
init {
// initializer block ...
}
constructor (name: String, age: Int) : this(name) {
// ...
}
}
```
기본 생성자도 보조 생성자도 정의되지 않은 클래스의 경우, 매개 변수가 없는 기본 생성자가 자동으로 생성되며, 자동으로 만들어진 생성자는 public의 접근 권한으로 지정됩니다.
## 객체의 인스턴스화
> 코틀린에는 `new` 키워드가 없습니다.
```kotlin
val charlie = Person("Charlie")
```
## 프로퍼티
`var` 또는 `val`을 사용해서 클래스의 프로퍼티를 선언합니다.
```kotlin
class Person {
val name: String
var age: Int
}
```
프로퍼티의 겟터와 셋터를 지정할 수 있습니다.
```kotlin
class SomeClass {
var someProperty: String
get() = this.toString()
set(value) {
// ...
}
}
```
겟터와 셋터에 접근한정자를 지정하거나 어노테이션을 지정하는 경우에 다음과 같이 할 수 있습니다.
```kotlin
var someProperty: String = "abcd"
private set // 셋터는 기본 구현을 사용하며, 접근은 private으로 제한
```
### 필드
`field`는 프로퍼티의 값을 임시로 저장해두는 공간입니다. `field`는 프로퍼티의 접근자에서만 사용할 수 있습니다.
```kotlin
var counter = 0
set(value) {
if (value >=0) field = value
// counter = value 라고 하면 안됩니다.
}
```
### 컴파일 타임 상수
컴파일 타임에만 사용되는 상수에는 `const` 키워드를 붙여서 컴파일 타임 상수로 만듭니다.
```kotlin
const val MY_VALUE: String = "..."
```
### 지연 초기화 프로퍼티 또는 변수
```kotlin
lateinit var subject: Subject
```
## 추상 클래스
추상 클래스는 `abstract`를 사용해서 정의합니다. 추상 클래스는 상속을 전제로 하므로 `open`을 명시할 필요가 없습니다.
오버라이드하는 함수 앞에는 `override` 키워드를 붙입니다.
```kotlin
abstract class Shape {
abstract fun draw()
}
class Rectangle : Shape() {
override fun draw(){
// ...
}
}
```
추상 클래스가 아닌 클래스를 상속하는 추상 클래스도 만들 수 있습니다.
```kotlin
open class Shape {
open fun draw(){
// ...
}
}
abstract class SomeShape : Shape() {
abstract override fun draw()
}
```
## 인터페이스
인터페이스는 구현된 메서드를 가질 수도 있으며, 프로퍼티를 가질 수도 있습니다.
```kotlin
interface MyInterface {
val prop1: Int // 추상 프로퍼티
val prop2: String // 겟터가 구현된 프로퍼티
get() = "foo"
fun bar()
fun foo() {
// 바디를 가질 수도 있습니다.
}
}
```
### 다중 상속시 충돌의 해결
```kotlin
interface A {
fun foo() { print("A") }
fun bar()
}
interface B {
fun foo() { print("B") }
fun bar()
}
class C : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
override fun bar(){
print("C")
}
}
```
## 상속
클래스의 상속은 `:`을 사용해서 표현합니다.
클래스는 기본적으로 `final`이므로 상속 가능하게 하려면 클래스 선언 앞에 `open`을 지정해야 합니다.
```kotlin
open class Shape
class Rectangle(var height: Double, var length: Double): Shape(){
var perimeter = (height + length) * 2
}
```
```kotlin
open class Base(p: Int)
class Derived(p: INt) : Base(p)
```
만일, 클래스에 기본 생성자가 없다면 각각의 보조 생성자에서 `super`를 통해서 호출해야 합니다.
```kotlin
class Dog : Animal {
constructor(name: String) : super(name)
constructor(name: String, age: Int) : super(name, age)
}
```
상속 가능한 클래스와 오버라이드 가능한 메서드 앞에는 `open`을 붙이니다. 그리고, 오버라이드 하는 메서드 앞에는 `override`를 붙입니다.
오버라이드 한 메서드는 `open`상태이므로, 자식 클래스에서 오버라이드를 제한하려면 `final`을 붙여야 합니다.
```kotlin
open class Rectangle() : Shape() {
final override fun draw() {
// ...
}
}
```
메서드와 마찬가지 방식으로 프로퍼티도 오버라이드할 수 있습니다.
```kotlin
open class Shape {
open val vertexCount: Int = 0
}
class Rectangle : Shape() {
override val vertexCount = 4
}
```
## Data 클래스
```kotlin
data class User(val name: String, val age:Int)
```
## Sealed 클래스
```kotlin
sealed interface Error
sealed class IOError(): Error
```
## Inner 클래스
```kotlin
class Outer {
private val bar: Int = 1
inner class Inner {
fun foo() = bar
}
}
```
## 인라인 클래스
```kotlin
@JvmInline
value class Password(private val s: String)
```

View File

@@ -0,0 +1,60 @@
# 컬렉션
- listOf()
- setOf()
- mapOf()
- mutableListOf()
- mutableSetOf()
- mutableMapOf()
```kotlin
val numberSet = setOf("one", "two", "three")
val emptySet = mutableSetOf<String>()
```
```kotlin
val numberMap = mapOf("one" to 1, "two" to 2, "three" to 3)
```
## 빌더 함수
- buildList()
- buildSet()
- buildMap()
```kotlin
val map = buildMap{
put("a", 1)
put("b", 2)
}
```
## 빈 컬렉션
- emptyList()
- emptySet()
- emptyMap()
```kotlin
val empty = emptyList<String>()
```
## 복제
- toList()
- toMutableList()
- toSet()

View File

@@ -0,0 +1,95 @@
# 조건문
## if .. else if .. else ..
코틀린의 `if`문은 표현식이므로 값을 반환합니다. 그래서 삼항 연산자를 대신할 수 있습니다.
```kotlin
if (a > b) c = a
```
```kotlin
if (a > b) {
c = a
} else {
c = b
}
```
```kotlin
c = if (a > b) a else b
```
`if` 구문에 블록을 사용하는 경우에는 마지막 표현식이 반환값이 됩니다.
```kotlin
val c = if (a > b) {
doSomething()
a
} else {
doSomething()
b
}
```
`if`가 값을 반환하는 경우에는 반드시 `else`도 필요합니다.
## when
다른 언어의 `switch.. case` 구문과 유사합니다. `if`와 마찬가지로 표현식이므로 값을 반환합니다.
자바와 달리, `break`를 사용하지 않습니다.
```kotlin
when(x) {
1 -> print("x = 1")
2 -> print("x = 2")
else -> {
print("x != 1 and x != 2")
}
}
```
`if`와 마찬가지로 `when`이 값을 반환하는 경우에는 반드시 `else`도 필요하지만, `when``enum`에 대해서 사용될 때에는 `else`가 없어도 됩니다.
```kotlin
enum class Bit {
ZERO, ONE
}
val value = when(someBitValue) {
Bit.ZERO -> 0
Bit.ONE -> 1
}
```
콤마(',')를 사용해서 여러 조건을 묶을 수 있습니다.
```kotlin
when(x) {
1, 2 -> print("x = 1 or x = 2")
else -> {
print("x != 1 and x != 2")
}
}
```
조건에 표현식을 사용할 수도 있습니다.
```kotlin
when(x) {
s.toInt() -> print("..")
else -> print(".....")
}
```
`in`또는 `!in`과 함께라면, 레인지나 컬렉션을 활용할 수도 있습니다.
```kotlin
when(x) {
in 1..10 -> print("..")
in someNumbers -> print("....")
!in 10..20 -> print(".....")
else -> print(".........")
}
```

View File

@@ -0,0 +1,18 @@
# 위임
```kotlin
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main(){
val b = BaseImpl(10)
Derived(b).print()
}
```

50
Writerside/topics/Enum.md Normal file
View File

@@ -0,0 +1,50 @@
# 열거형
```kotlin
enum class Direction {
NORTH, SOUTH, EAST, WEST
}
enum class Color(val rgb: Int) {
RED(0xff0000),
GREEN(0x00ff00),
BLUE(0x0000ff)
}
```
```kotlin
val dir = Direction.valueOf("NORTH")
for (item in Direction.values()) {
// ...
}
```
## 익명 클래스
```kotlin
enum class State {
WAITING {
override fun signal() = TALKING
},
TALKING {
override fun signal() = WAITING
}
abstract fun signal(): State
}
```
## 인터페이스
```kotlin
enum class IntArithmetics : BinaryOperator<Int>, IntBinaryOperator {
PLUS {
override fun apply(t: Int, u: Int): Int = t + u
},
TIMES {
override fun apply(t: Int, u: Int): Int = t * u
};
override fun applyAsInt(t: Int, u: Int) = apply(t, u)
}
```

View File

@@ -0,0 +1,31 @@
# 예외
코틀린에는 'Checked exception'이 없습니다. 따라서, 자바와 달리, 의무적으로 예외를 처리할 필요가 없습니다.
## 예외 발생
```kotlin
throw Exception("Oops!")
```
## 예외 처리
```kotlin
try {
// ...
} catch(e: SomeException) {
// ...
} finally {
// ...
}
```
`try` 구문도 표현식이므로 값을 반환할 수 있습니다.
```kotlin
val a: Int? = try {
input.toInt()
} catch (e: NumberFormatException) {
null
}
```

View File

@@ -0,0 +1,72 @@
# 함수
```kotlin
fun functionName(p1: Type1, p2: Type2, ...): ReturnType {
...
return result
}
```
```kotlin
fun sum(a: INt, b: Int): Int {
return a + b
}
```
> 함수 선언은 `fun`으로 시작합니다.
그 뒤에 함수 이름을 명시하고, 매개변수를 나열합니다. 각각의 매개변수 이름 뒤에 자료형을 써줍니다. 그리고 반환형의 자료형을 명시합니다.
```kotlin
fun sum(a:Int, b:Int) = a + b
```
함수의 바디는 블럭 대신 표현식이 될 수도 있습니다.
반환형이 추론 가능한 경우에는 생략할 수도 있습니다.
```kotlin
fun printSum(a:Int, b:Int): Unit {
println(a + b)
}
```
```kotlin
fun printSum(a:Int, b:Int) {
println(a + b)
}
```
반환 값이 없는 함수의 리턴 타입으로 `Unit`을 사용합니다. 물론, `Unit` 타입은 생략할 수 있습니다.
함수의 매개변수는 기본값을 가질 수 있습니다.
```kotlin
fun read(
b: ByteArray,
offset: Int = 0,
length: Int = b.size
){
// ...
}
```
전달하는 매개 변수를 명시해야 할 수도 있습니다.
```kotlin
fun foo(
bar: Int = 0,
baz: Int
) {
// ...
}
foo(baz = 1)
```
## Function 타입
## 람다
## 인라인 함수
## 연산자 오버로딩

View File

@@ -0,0 +1,58 @@
# 인터페이스
인터페이스는 구현된 메서드를 가질 수도 있으며, 프로퍼티를 가질 수도 있습니다. 인터페이스는 `interface` 를 사용해서 선언합니다.
```kotlin
interface MyInterface {
val prop1: Int // 추상 프로퍼티
val prop2: String // 겟터가 구현된 프로퍼티
get() = "foo"
fun bar()
fun foo() {
// 바디를 가질 수도 있습니다.
}
}
```
## 다중 상속시 충돌 문제의 해결
```kotlin
interface A {
fun foo() { print("A") }
fun bar()
}
interface B {
fun foo() { print("B") }
fun bar()
}
class C : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
override fun bar(){
print("C")
}
}
```
## 함수형 인터페이스
함수형 인터페이스란, 하나의 추상 메서드만을 가진 인터페이스입니다. `fun interface`를 사용해서 선언합니다.
```kotlin
fun interface KRunnable {
fun invioke()
}
```
함수형 인터페이스는 람다 표현식에서 유용하게 사용됩니다.
```kotlin
fun interface IntPredicate {
fun accept(i: Int): Boolean
}
val isEven = IntPredicate {it % 2 == 0 }
```

72
Writerside/topics/Loop.md Normal file
View File

@@ -0,0 +1,72 @@
# 반복
## for .. in ..
```kotlin
for (item: Int in array){
// ...
}
```
레인지와 함꼐 사용할 수도 있습니다.
```kotlin
for (i in 1..10){
// ...
}
for (i in 6 downTo 0 step 2){
// ...
}
```
인덱스가 필요한 경우에는 `indices` 또는 `withIndex()`를 사용해서 다음과 같이 할 수 있습니다.
```kotlin
for (i in array.indices) {
println(array[i])
}
```
```kotlin
for ((index,value) in array.withIndex()) {
println("element[$index] is $value.")
}
```
## while
```kotlin
while (x > 0) {
// ...
}
```
### do .. while
```kotlin
do {
// ...
} while (x > 0)
```
# 분기
- return
- break
- continue
## 라벨
표현식의 앞에 '@'을 사용해서 라벨을 붙여 둔 다음, `break``continue` 뒤에 '@'을 사용해서 점프할 라벨 위치를 지정할 수 있습니다.
```kotlin
loop@ for (i in 1..10) {
for (j in 1..10) {
if (...) break@loop
}
}
```

View File

@@ -0,0 +1,35 @@
# Object
```kotlin
val charlie = object {
val name = "Charlie"
val age = 13
override fun toString() = "$name is $age-year-old."
}
```
## 오브젝트 선언
싱글턴 패턴에 사용됩니다.
```kotlin
object MyObject {
fun doSomething() {
//...
}
}
MyObject.doSomething()
```
## 컴패니언 오브젝트
```kotlin
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
val x = MyClass.Companion
```

255
Writerside/topics/Type.md Normal file
View File

@@ -0,0 +1,255 @@
# 자료형
> 자바와 달리 원시 자료형이 없으면 모든 자료형이 객체입니다.
## 숫자형
### 정수형
- Byte
- Short
- Int
- Long
### 부동 소수형
- FLoat
- Double
### 형 변환
- toByte()
- toShort()
- toInt()
- toLong
- toFloat()
- toDouble()
### 연산자
#### 산술 연산자
- +, -, *, /, %
#### 비트 연산자
- shl
- shr
- ushr
- and
- or
- xor
- inv
#### 비교 연산자
- ==, !=
- <, >, <=, >=
## 부호없는 정수형
- UByte
- UShort
- UInt
- ULong
```kotlin
val a: UShort = 1u
val b = 1UL
```
## 부울형
- Boolean
#### 연산자
- ||
- &&
- !
## 문자형
- Char
```kotlin
val a: Char = '\t'
```
## 문자열형
- String
```kotlin
val s = "abcd"
```
문자열을 구성하는 각 문자는 배열 형태의 첨자(`str[i]')를 통해서 접근할 수 있으며, `for`를 사용해서 반복할 수도 있습니다.
```kotlin
for (ch in str) {
println(ch)
}
```
### Raw String
```kotlin
val text = """
Hello, "World"!
This is a raw string.
"""
```
각 줄 앞의 공백을 제거하려면, `trimMargin()`을 사용합니다.
```kotlin
val text = """
|Hello, "World"!
|This is a raw string.
""".trimMargin()
```
줄의 시작을 나타내는 기본값인 '|' 대신 다른 문자를 사용하려면, `trimMargin(">")` 같은 형식으로 사용할 수 있습니다.
### 템플릿
문자열 템플릿에 변수를 삽입하려는 경우에는 `$`를 사용합니다. 경우에 따라서 `{}`를 사용해서 표현식을 묶어 줄 수 있습니다.
```kotlin
var a = 1
val str1 = "a is $a"
a = 2
val str2 = "${str1.replace("is", "was")}, but now is $a"`
```
문자열 템플릿은 Raw String에도 사용할 수 있습니다. Raw String에서 '$' 문자를 표시하려는 경우에는 다음과 같이 사용합니다.
```kotlin
val text = """
The price is ${'$'}9.99
""".trimMargin()
```
## 배열
> 코틀린에서 배열은 `Array<T>`로 표현합니다.
기본적으로 `get()`, `set()` 함수가 있으며 연산자 오버로딩이 되어 첨자 표현(`[]`)을 사용할 수 있습니다.
### 배열의 생성
```kotlin
val array1 = arrayOf(1, 2, 3, 4) // [1,2,3,4]
val array2 = arrayOfNulls(4) // [null,null,null,null]
```
```kotlin
val array = Array(5) {i -> (i*i).toString()}
```
### 원시타입 배열
- ByteArray
- ShortArray
- IntArray
```kotlin
val array1: IntArray = intArrayOf(1,2,3)
val array2 = IntArray(5) // [0,0,0,0,0]
val array3 = IntArray(5) {43} // [43,43,43,43,43]
```
## Any
코틀린에서 모든 클래스의 부모 클래스는 `Any`입니다. 자바에서의 최상위 객체가 `Object`인 것과 마찬가지입니다. `Any`는 다음 메서드를 갖고 있습니다.
- equals()
- hashCode()
- toString()
## 타입 판별 연산자
- `is`, `!is`
```kotlin
if (obj is String) {}
```
### 자동 형변환
자료형이 판별된 이후에는 자동으로 형변환이 이루어집니다.
```kotlin
if (x is String && x.length > 0){
print(x.length)
}
```
## 형변환 연산자
- `as`
- `as?`
```kotlin
val x: Stirng = y as String // x, y 모두 nullable이 나닌 경우
val x: String? = y as String? // x, y 모두 nullable인 경
```
`as?`를 사용하면 형변환이 실패한 경우에 null을 반환합니다.
```kotlin
val x: String? = y as? String
```
## Type alias
타입 얼라이어스를 사용하면 자료형의 이름을 다른 이름으로 대신 사용할 수 있습니다.
```kotlin
typealias NodeSet = Set<Network.Node>
```
```kotlin
class A {
inner class Inner
}
typealias AInner = A.Inner
```

View File

@@ -0,0 +1,98 @@
# 변수
- 변수는 `var`를 사용해서 선언합니다.
- 상수는 `val`을 사용해서 선언합니다.
> 자바와 달리, 변수를 최상위 수준에 선언할 수도 있습니다.
## var
```kotlin
var a: Int = 1 // 선언과 동시에 값을 할당
var b = 2 // 자료형이 추론 가능한 경우 생략 가능
var c: Int // 값이 나중에 할당되는 경우에는 자료형을 지정해 줘야 합니다.
c = 3
```
## val
```kotlin
val a: Int = 1
val b = 2
val c: Int
c = 3
```
## 자료형
- Byte
- Short
- Int
- Long
- Float
- Double
- Boolean
- Char
- String
```kotlin
var price = 1200
var rate = 1.1
var product = "Candy"
```
```kotlin
var price: Int = 1200
var rate: Double = 1.1
var product:String = "Candy"
```
## Null 안정성
변수 또는 상수가 null 값을 가질 수 있게 하려면 자료형 뒤에 `?`를 붙입니다.
```kotlin
var a: String = "abc"
a = null // BAD: can not be a null
var b: String? = "abc"
b = null // OK. nullable
```
## Null 체크
```kotlin
val v = if (b != null) b.length else -1
```
## Nullable 값의 안전한 사용
```kotlin
println(b?.length)
// b가 null인 경우에는 null을 반환하고, 아니면 b의 length를 반환
```
## 엘비스 연산자
```kotlin
val v: Int = if (b != null) b.length else -1
val v = b?length ?: -1
```
## Not-Null 단언
```kotlin
val l = b!!.length
// b가 널이 아님이 확실할 때 사용합니다. b가 null이면 예외가 발생합니다.
```

View File

@@ -0,0 +1,113 @@
# Hello, Kotlin!
```kotlin
package com.elex_project.examples
fun main(){
// Comment
println("Hello, Kotlin!")
}
```
- 줄 끝에 세미콜론이 필요 없습니다.
- 화면에 한 줄 출력하는 `println()` 함수입니다.
## 패키지 선언과 임포트
```kotlin
package com.elex_project.examples
import kotlin.text.*
```
- 소스 파일의 맨 처음에 패키지 선언이 되어야 합니다. 패키지 선언이 없는 경우에는 이름없는 디폴트 패키지에 속한 것으로 간주됩니다.
- 자바와 달리, 패키지 이름은 파일의 디렉토리 구조와 일치할 필요가 없습니다.
### 기본 임포트
다음의 패키지는 자동으로 임포트됩니다.
- kotlin.*
- kotlin.annotation.*
- kotlin.collections.*
- kotlin.io.*
- kotlin.ranges.*
- kotlin.sequences.*
- kotlin.text.*
- java.lang.*
- kotlin.jvm.*
임포트할 클래스의 이름이 겹치는 등의 경우에 `as`를 사용해서 임포트할 이름을 변경할 수 있습니다.
```kotlin
import com.examples.Message as TestMessage
```
## 메인 함수
```kotlin
fun main() {
}
```
- 자바와 달리, 메인 함수는 클래스에 종속되어 있지 않습니다.
- 함수 선언은 `fun`으로 시작합니다.
```kotlin
fun main(args: Array<String>){
}
```
- Array<String> 형태로 임의 갯수의 매개 변수를 전달 받을 수 있습니다.
## 표준 출력
```kotlin
print("Hello, ")
print("World!")
```
- 전달 받은 변수를 화면에 출력하는 함수 입니다.
```kotlin
println("Hello, World!")
```
- `print()`와 마찬가지로 화면에 출력하며, 다만 맨 뒤에 줄바꿈도 출력합니다.
## 코멘트
한 줄 주석과 여러 줄 주석이 지원됩니다.
```kotlin
// this is a comment
/*
This is
a multi-line comment.
*/
```
여러 줄 주석은 중첩될 수도 있습니다.
```kotlin
/*
This is
/* nested comment */
a multi-line comment.
*/
```