반응형

1. interface

interface Person {
	
	// (1)
	var age: Int
	
	// (2)
	val height: Int
			get() {
				return 30
			}
	
	// (3)
	fun earn(): Int
	
	// (4)
	fun talk() = println("말한다!")
	
	// (5)
	fun walk() {
		println("걷는다")
	}
	
	// (5)
	fun greet(): String {
		return "안녕하세요"
  }
  
  @JvmStatic
  fun hello() = println("안녕!")
  
  companion object {
	  fun hello_en() = println("hello!")
  }
}

코틀린의 인터페이스는 자바 유사하나 조금 차이가 있다

 

1. 추상 프로퍼티 선언 가능
    - var를 선언하는 경우 getter, setter를 반드시 구현해야한다(기본 구현 필수)

    - 계산 프로퍼티

    - 백킹 필드(backing field)가 존재하지 않음

    - 추상 프로퍼티에 대한 default 구현 가능 get()

 

2. static이 없어 companion object 또는 @JvmStatic 어노테이션으로 가능

3. default 대신 일반적인 함수 선언과 동일하게 선언 하고 몸체(body)가 있는 경우 default 함수로 판단

 

* 인터페이스 다중 상속 시 동일한 시그니처에 대한 처리는 명시적으로 super 호출 함으로서 해결 할 수 있다

interface A {
    fun run() = println("A Run")
}

interface B {
    fun run() = println("B Run")
}

class C : A, B {
    override fun run() {
        super<A>.run()
    }
}

 

 

 

반응형
반응형

1. object

object 키워드는 코틀린에서 클래스를 정의하면서 동시에 객체를 생성하는 키워드 이다

class 자리에 object 키워드를 사용하면 된다

 

1) 객체 선언

  • class 대신 object 키워드를 사용하면 클래스를 선언함과 동시에 객체를 생성하게되고 이는 싱글톤 객체가 된다
object Counter {
	private var count: Int = 0
	
	fun plus() {
		count++
	}
	
	fun getCount() = count
}

fun main() {
	println(Counter.getCount())
	Counter.plus()
	Counter.plus()
	println(Counter.getCount())
}

 

2) 객체 식

  • 익명클래스를 통해 객체를 생성할 때 사용
interface Person {
	fun work()
}

fun main() {
	val worker = object: Person {
		override fun work() {
			println("일한다!")
		}
	}
	
	worker.work()
	
}

 

3) 동반 객체(companion)

  • 클래스의 객체들이 공유해야하는 메소드나 프로퍼티를 정의할 때 사용
  • Factory Method 패턴 사용시 활용 가능
class User private constructor(val id: Int) {
    companion object {
        fun create(id: Int): User {
            return User(id)
        }
    }
}

fun main() {
    val user = User.create(1111)
    println(user.id)  // 1111
}

마치 자바의 static 키워드를 사용하는 것과 비슷한 효과가 나온다(코틀린에는 static이 존재하지 않는다)

컴패니언(companion) 객체는 최종적으로 jvm 바이트코드로 컴파일(.class) 될 때 static 멤버로 컴파일 된다

반응형
반응형

1. 상속(inherit)

코틀린의 상속은 자바와 매우 비슷하다

 

자바의 상속

class Person {
	private final name;
	
	public Person(name) {
		this.name = name;
	}
}

public class Kim extends Person {
	public Kim(name) {
		super(name);
	}
}

자바의 상속은 extends 키워드를 통해 가능하며, 이때 super를 통해 부모의 생성자를 호출할 수 있다

 

코틀린의 상속

(1)
open class Person(val name: String)

class Kim(name: String): Person(name)

(2)
open class Person(open val name: String)

class Kim(override val name: String): Person(name)

(3)
open class Person(val name: String)

class Kim(val name: String): Person(name)

(4)
open class Person(val name: String)

class Kim: Person{
	constructor(name: String): super(name) {
		println("생성자 호출됨")
	}
	constructor(): super("김철수")
}

코틀린은 클래스 생성의 끝부분에 :와 함께 상속하고자 하는 클래스를 지정하고 해당 클래스에 대한 주생성자에 맞게 값이 할당되도록 작성하면 된다

이때 부모 클래스의 앞에 open 키워드가 존재해야만 한다

자식 클래스에서 부모 클래스의 생성자를 호출하는 방법으로는 주생성자에서 호출할 수 도 있고 부생성자에서도 가능하다

자바와 다르게 코틀린의 super는 주생성자 또는 부생성자 옆에만 붙일 수 있다

코틀린의 상속도 자바와 마찬가지로 하나의 클래스에 대해서만 상속이 가능하다(다중 상속을 지원하지 않는다)

반응형
반응형

1. 클래스

코틀린에서 클래스를 작성하는 방법

class Person(val name: String, val age: Int) {
	fun hello() {
		println("hello I am ${name} and I am ${age} years old")
	}
}

코틀린의 클래스를 작성하는 방법은 자바와 유사하지만 생성자 부분에 있어서 조금 차이가 있다

자바에서 생성자는 클래스 명으로된 생성자를 클래스 내부에 작성하는 반면, 코틀린의 경우 클래스를 선언하는 부분에서 생성자의 파라미터를 지정하는 식으로 작성한다

1) 생성자

코틀린의 생성자는 주생성자와 부생성자로 나뉜다

  • 주생성자 : 클래스를 선언하는 부분에 작성된 것
  • 부생성자 : construct 키워드를 통해 작성된 것, 여러개 가질 수 있음
(1)
class Person(val name: String, val age: Int) {} // 주생성자

(2)
class Person {
    var name: String
    var age: Int

    constructor(name: String, age: Int) { // 부생성자 1
        this.name = name
        this.age = age
    }
    
    constructor(name: String) { // 부생성자 2
	    this.name = name
	    this.age = 10
}

(2)의 경우는 문제가 생길 수 있다 따라서 위처럼하기 보다는 프로퍼티에 기본 값을 할당하는 것이 더 낫다

주생성자를 통해 객체가 생성될 때 자바의 경우 생성자에 로직을 넣어서 처리할 수 있다

코틀린에서는 주생성자에 로직을 넣을 수 없는데, 이를 위해 init이라는 초기화 블록이 존재한다

 

이를 통해 객체 생성 시점에 초기화 로직을 작성 할 수 있다

class Person(val name: String, var age: Int) {

    init { // 초기화 블록
        println("Person is created: $name")
    }
}

 

2) getter, setter

코틀린에서는 기본적으로 프로퍼티에 대해 자동으로 getter, setter 가 생성 된다

(val의 경우 getter만 생성)

 

이렇게 생성된 getter와 setter를 아래와 같이 커스터마이징할 수 있다

var name: String
    get() {
        println("called get")
        return field
    }
    set(value) {
        println("called set")
        field = value
    }

 

field라고하는 식별자를 통해 프로퍼티의 값을 할당하거나 읽는 것을 볼 수 있다

field는 백킹 필드를 참조하기 위한 식별자로 프로퍼티의 실제 저장 공간을 의미한다

 

그렇다면 주생성자를 통해 만들어진 필드에 대해서는 어떻게 getter와 setter를 커스터마이징 할 수 있을까

class Person(private var _name: String) {
		var name: String
				get() {
					println("called get")
					return _name
				}
				set(value) {
					println("called set")
					_name = value
				}
}

 

이처럼 계산 프로퍼티를 이용하여 원래 백킹 프로퍼티를 숨기고, get, set을 커스텀하여 사용할 수 있다

 

백킹 프로퍼티:

  • 실제 데이터를 저장하는 공간이 존재
  • 값 변경 가능(var의 경우)
  • 데이터를 필드에서 직접 읽음

계산 프로퍼티:

  • 데이터를 저장하는 공간 없음
  • 데이터 접근 시 계산 프로퍼티의 getter를 거쳐서 접근

백킹 프로퍼티와 계산 프로퍼티의 차이는 크게 보면 데이터를 실제로 저장하는지 안하는지로 구분할 수 있다

반응형

'공부' 카테고리의 다른 글

Kotlin 기본 문법 정리 - object  (2) 2025.07.23
Kotlin 기본 문법 정리 - 상속  (0) 2025.07.21
Kotlin 기본 문법 정리 - 함수  (0) 2025.07.18
Kotlin 기본 문법 정리 - 타입과 변수  (0) 2025.07.17
Gradle 개념과 역할  (0) 2025.07.15
반응형

1. 함수

코틀린에서 함수는 fun 키워드를 통해 정의할 수 있다

java에서는 함수를 정의하기 위해서는 class 내에서 함수를 정의할 수 있지만, 코틀린에서는 클래스 외부에서도 함수를 정의할 수 있다.

  • 자바의 경우 함수는 class 내부에 종속된 상태로 구현 가능
  • 코틀린은 class에 종속되지 않고 함수를 구현할 수 있음

코틀린에서 함수는 자바와 동일하게 함수 파라미터와 반환형을 가지는데 아래와 같이 정의할 수 있다

(1)
fun add(x: Int = 1, y: Int): Int {
	return x+y
}

(2)
fun add(x:Int, y: Int): Int = x+y

(3)
val opr: (Int, Int) -> Int = {a, b -> a + b}

val opr = {a: Int, b: Int -> x+y}

 

(1) 코틀린의 일반적인 함수 선언

  • 파라미터를 지정할 때는 형식을 지정해야한다
  • 파라미터의 default value를 지정할 수 있다
    • 함수를 사용할 때 파라미터 명을 지정하여 호출할 수 있다. 이때 파라미터에 값을 대입하지 않는 경우 default value가 존재하면 해당 파라미터의 값은 default value가 된다 ex) add(y=10) ⇒ x = 1, y = 10 파라미터들의 값이 대입되는 것과 같다
  • 함수의 반환형을 지정해야한다
    • 반환이 없다면 반환 타입을 생략해되지만 이럴 경우 반환 타입은 Unit이 된다

(2) (1)의 함수를 단일 식 함수로 선언한 것이다

 

(3) 람다식을 이용하여 함수를 정의한 것이다

  • 1번째 케이스는 파라미터 타입과 반환 타입을 지정하고 람다식으로 함수를 작성한 것이다
  • 2번째 케이스에는 반환 타입이 생략되었는데 이는 람다식의 계산 결과를 통해 반환 타입이 추론 된다

위의 예시에서 보면 한가지 특이해보이는 것이 있는데 람다식으로 작성한 함수를 변수에 할당하는것을 볼 수 있다

코틀린에서 함수는 일급 시민(first-class citizen)으로 함수를 변수에 대입할 수 있다

 

2. 일급시민

일급 시민은 언어에서 개체를 하나의 완전한 값으로 취급하고 다룰 수 있는 것이다

 

일급시민의 조건

  • 변수에 할당 가능
  • 함수의 인자로 전달 가능
  • 함수의 반환값으로 사용 가능
  • 동적으로 생성하거나 조작 가능

자바의 경우 함수는 일급시민이 아니다

물론 자바8 이후에는 람다와 함수 인터페이스가 들어왔지만 이는 함수형 프로그램을 위한 것이다

이를 통해 자바는 함수 인터페이스를 익명 클래스로 구현함으로서 함수형 프로그래밍이 가능해졌다

 

public class FunctionalP {
	public static BiFunction<Integer, Integer, Integer> add() {
		return (x, y) -> (x + y);
	}
	
	public static void main(String[] args) {
		
		// 람다를 통한 익명 클래스 구현
		BiFunction<Integer, Integer, Integer> func1 = (x, y) -> x+y;
		BiFunction<Integer, Integer, Integer> func2 = add();
		
		System.out.println(func1.apply(1,2));
		System.out.println(func2.apply(3,4));
	}
}

 

자바에서 함수가 일급시민이 아닌 이유

  • 독립 객체가 아니다 독립 객체 인 것처럼 보이나 실제로는 인터페이스를 구현한 것
  • 자바에서 함수는 값이 아닌 클래스 내 행동(메소드)이다
반응형
반응형

코틀린은 컴파일 시 타입을 체크하는 강타입 언어 이다

 

1. 타입(Type)

코틀린에서는 원시 타입(Primitive Type)을 사용하지 않는다

객체 타입으로만 처리한다

 

정수 타입

- Int, Byte, Short, Long

실수 타입

- Float, Double

문자 타입

- Char

불리언 타입

- Boolean

문자열 타입

- String

 

2. 변수

코틀린에서 변수를 선언하는 방법은 var과 val로 두가지가 있다

 

var(variable)의 경우는 변수에 저장된 값을 변경할 수 있다

// var 변수의 값 변경 예시

var a:Int = 10	// 변수 a를 선언하면서 10으로 초기화
a = 20		// 변수 a에 저장된 값을 20으로 변경

 

val(value)은 상수로 선언 시 값을 초기화하고 이후 값을 변경 할 수 없다(상수 이기 때문)

// val 상수 값 변경 불가능 예시

val b = 10	// 상수 b를 선언하고 값을 10으로 초기화, 타입 추론으로 Int타입 명시 생략
b = 20		// 상수 b의 값을 20으로 변경하려고 함으로 컴파일 불가능

 

타입 추론

코틀린의 경우 타입 추론을 지원한다

그렇기 때문에 대입하는 값에 따라 선언 시점에 타입이 지정된다(선언시 지정된 타입은 이후 변경되지 않음)

// 타입추론 예시

val a:Int = 10	// 타입을 Int로 명시
val a = 10	// 타입을 생략했으나 타입 추론에 의해 Int

 

반응형

'공부' 카테고리의 다른 글

Kotlin 기본 문법 정리 - 클래스(Class)  (0) 2025.07.21
Kotlin 기본 문법 정리 - 함수  (0) 2025.07.18
Gradle 개념과 역할  (0) 2025.07.15
Redis 개념 정리 및 Spring 활용  (0) 2025.07.15
[DB] S/X Lock  (0) 2025.06.24

+ Recent posts