일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- OpenFeign
- FeignClients
- 멀티스레드
- 오블완
- OAuth2.0
- 코드로 배우는 스프링 부트 웹 프로젝트
- 2024년 상반기 회고
- ExceptionHandlerFilter
- Spring Reactive Programming
- 멀티프로세싱
- ExecutorService
- springboot
- 비사이드프로젝트
- 도메인 주도 설계(DDD) 기반 마이크로서비스(MSA) 모델링
- REDIS
- 비동기
- 네이버클라우드 서버
- Apple 로그인
- Spring Security
- 사이드 프로젝트
- asciidoctor
- JWT
- 멀티태스킹
- microsoft
- Spring Cloud OpenFeign
- 스레드
- spring boot
- 티스토리챌린지
- querydsl
- 프로세스
- Today
- Total
기록하기
[Kotlin 기본 정리] Classes, Constructors, Companion Object 본문
혼자 만들어 보려는 toy project 에는 Kotlin 을 활용해서 만들어보려고 한다.
그러기 위해서는 일단 기초적인 내용 학습과 더불어 간단한 web application 을 만들어봐야겠다고 생각을 했고, 학습을 위해 인프런 강의 2개를 수강하고 있다.
수강을 하면서 간단하게 내용을 정리해보려는데 강의 내용과 코틀린 공식 문서를 참고해서 내용 정리를 해보려고 한다.
(* Kotiln 을 코틀린이라고 명시함.)
Classes
먼저, Class 는 간단한데 코틀린에서는 class 라는 키워드를 활용해서 정의하며 body 가 없으면 {} 는 생략 가능하다.
class Person(
//기본 생성자
val name: String,
var age: Int
) {
Constructors
위 예시를 보면 () 안에 작성한 내용을 확인할 수 있는데 이는 기본 생성자를 뜻한다.
기본 생성자는 클래스 헤더에서 클래스 인스턴스와 해당 속성을 초기화하며, constructor 라고 명시적으로 작성할 수도 있는데 만약 어떠한 annotation 이나 modifier 가 없다면 contructor 는 생략할 수 있다.
class Person constructor(name: String, age: Int) {}
이때 기본 생성자와 관련해서 초기화 블록과 부생성자를 같이 이해해야 한다.
초기화 블록
클래스 헤더에 작성한 기본 생성자에는 실행 가능한 코드가 포함될 수 없는데, 만약 객체 생성 중에 어떤 코드를 실행하려면 초기화 블록을 사용해야한다.
fun main() {
val person = Person("park", 20)
}
class Person(
//기본 생성자
val name: String,
var age: Int
) {
init {
if (age <= 0) {
//코드 실행
}
println("초기화 블록")
}
}
이렇게 작성한 뒤 main 함수를 실행해보면 아래와 같이 출력되는 것을 확인할 수 있다.
부생성자
코틀린에서는 기본 생성자와 하나 이상의 보조 생성자가 있을 수 있다.
여기서 기본 생성자와 부생성자를 같이 사용한다면 아래와 같이 작성해볼 수 있고, 여러 부생성자를 작성할수도 있다.
fun main() {
val person = Person()
}
class Person(
//기본 생성자
val name: String,
var age: Int
) {
init {
if (age <= 0) {
//코드 실행
}
println("초기화 블록")
}
//첫번째 생성자, 부생성자
constructor(name: String) : this(name, 1) {
println("부생성자1")
}
//두번째 생성자를 부르고 -> 두번째 생성자는 다시 첫번째 생성자를 부른다.
constructor() : this("홍길동") {
println("부생성자2")
}
}
부생성자는 기본 생성자를 호출하게 되는데 main 함수를 호출하면 결과는 아래와 같다.
그런데 부생성자 방식 보다는 default parameter 나 정적 팩토리 메소드 방법을 추천하는데 이는 이펙티브 자바에서도 나오는 내용이다. 생성자 보다 정적 팩토리 메소드를 활용하게 되면 다음과 같은 이점이 있다.
- 이름을 가질 수 있다.
- 호출될 때마다 인스턴스를 새로 생성하지 않아도 된다.
- 하위 객체를 반환할 수 있다.
- 매개변수에 따라 다른 클래스의 객체를 반환할 수 있다.
자바에서는 static 을 활용해서 정적 메소드를 작성할 수 있지만 코틀린에서는 static 키워드가 없다고 하여 이때 Companion Object 를 활용한다고 한다.
Companion Object
클래스와 동행하는 유일한 오브젝트로 동반객체도 하나의 객체로 간주된다. 그렇기 때문에 이름을 붙일 수도 있고, interface 를 구현할 수도 있다.
만약 다음과 같은 예시가 있다고 가정해보자
class Person(
var name: String,
var age: Int,
) {
// static 대신 companion object 사용한다.
companion object Factory {
//val => 런타임 시에 변수가 할당
//const => 컴파일 시에 변수가 할당, 진짜 상수에 붙이기 위한 용도, 기본 타입과 String 에만 붙일 수 있다.
private const val MIN_AGE = 1
fun newPerson(name: String): Person {
return Person(name, MIN_AGE)
}
}
}
이 정적 팩토리 메소드를 활용하기 위해서는 다음과 같은 방법을 활용할 수 있다.
- Factory 라는 이름이 있다면 Person.Factory.newPerson("ABC") 이렇게 사용할 수 있다.
- 그런데 만약 Factory 라는 이름이 없다면,
- newPerson 위에 @JvmStatic 을 붙여주어 Person.newPerson("ABC") 로 활용할 수 있다.
- 혹은 Person.Companion.newPerson("ABC") 로 작성해서 활용할 수 있다.
fun main() {
val person = Person.Factory.newPerson("ABC")
println(person.name)
println(person.age)
}
class Person private constructor(
var name: String,
var age: Int,
) {
// static 대신 companion object 사용한다.
companion object Factory {
//val => 런타임 시에 변수가 할당
//const => 컴파일 시에 변수가 할당, 진짜 상수에 붙이기 위한 용도, 기본 타입과 String 에만 붙일 수 있다.
private const val MIN_AGE = 1
fun newPerson(name: String): Person {
return Person(name, MIN_AGE)
}
}
}
출력을 해보면 다음과 같은 결과를 얻을 수 있다.
static 의 경우 자바와는 방법이 달라서 헷갈리는 부분이 있었지만, 활용 방법들이 다양해서 3가지의 방법으로 정적 팩토리 메소드를 만들 수 있다는 점이 유연한 부분인 것 같다.
다음에는 상속에 대한 이야기를 다뤄보도록 하겠다.