+ 항공대학교 김철기 교수님의 객체 지향 프로그래밍 과목 내용를 정리한 글입니다.
클래스
- 프로퍼티 (변수)와 메소드 (함수/연산)를 가지는 타입을 정의하는 단위
class Person {
// 프로퍼티
var firstName: String = "" // 이름
var familyName: String = "" // 성
var age: Int = 0 // 나이
// 메소드
fun fullName() = "$firstName $familyName" // 이름 + 성
fun showMe() {
println("${fullName()}: $age")
}
}
객체 (클래스의 인스턴스)의 생성
- Person 클래스 타입을 가지는 변수는 객체를 가리키는 참조자를 가진다.
// 인스턴스(객체)의 생성
fun main() {
val person = Person()
// person이라는 객체의 참조자 변수가 새롭게 생성한 Person 객체를 가리킴
person.firstName = "John"
person.familyName = "Doe"
person.age = 25
person.showMe() // John Doe: 25
}
생성자
- 클래스 머리 부분을 함수처럼 선언하여 생성자를 정의한다.
- 이렇게 정의하는 생성자는 1개만 가능하므로 '주생성자'라고 부른다.
fun main() {
val person =Person("John", "Doe")
println(person.fullName)
}
class Person(firstName: String, familyName: String) { // 클래스 생성자 정의
val fullName = "$firstName $familyName"
}
init 블록
- 하나의 식으로 표현하기 힘든 초기화 로직을 실행해야 할 때는 init 블록을 사용한다.
fun main() {
val person =Person("John Doe") // fullName을 생성자의 인자로 받아
println(person.firstName) // firstName 출력
}
class Person(fullName: String) { // 클래스 생성자 정의
val firstName: String
val familyName: String
init { // 클래스의 인스턴스가 생성될 때 호출. 클래스안의 요소 초기화한다.
val names = fullName.split(" ")
if (names.size != 2) {
throw IllegalArgumentException("Invalid name: $fullName")
// 매서드의 매개변수가 유효하지 않은 값 또는 범위를 가지고 있을 때 발생하는 예외
}
firstName = names[0]
familyName = names[1]
}
}
+ pdf 코드 오류: Illegal ArgumentException => IllegalArgumentException
프로퍼티의 초기화
- 프로퍼티가 초기화 되지 않을 가능성이 있다면 컴파일러가 에러를 발생한다.
=> 모든 프로퍼티는 반드시 초기화 돼야한다.
fun main() {
val person =Person("John Doe") // fullName을 생성자의 인자로 받아
println(person.firstName) // firstName 출력
}
class Person(fullName: String) { // 클래스 생성자 정의
val firstName: String
val familyName: String
init { // names의 크기가 2가 아닐 경우 firstName, familyName이 초기화 되지 않으므로 error 발생
val names = fullName.split(" ")
if (names.size == 2) {
firstName = names[0]
familyName = names[1]
}
}
}
주생성자 파라미터의 이용
- 주생성자 파라미터는 프로퍼티 초기화나 init 블록 안에서만 사용할 수 있다.
class Person(firstName: String, familyName: String) {
val fullName: String = "$firstName $familyName"
fun printFirstName() {
println(firstName) // Error: Name is not available here
// 생성자의 매개변수로만 정의되어 있기 때문에 클래스 내부의 다른 매서드나 프로퍼티에서 사용 불가
}
}
- 생성자의 파라미터 정의 앞에 val이나 var를 붙이면 파라미터를 프로퍼티로 만들 수 있다.
class Person(val firstName: String, val familyName: String) {
val fullName: String = "$firstName $familyName"
fun printFirstName() {
println(firstName) // Error: Name is not available here
// 생성자의 매개변수 + 프로퍼티로 정의했기 때문에 클래스 내부의 다른 매서드나 프로퍼티에서 사용 가능
}
}
부생성자
- 하나 이상의 생성자를 정의하고 싶을 때는 fun 함수 대신 constructor라는 예약어로 추가 생성자를 정의한다.
- Kotlin 개발자는 주생성자 개념에 익숙하기 때문에 부생성자만을 정의하는 것은 좋지 않다.
class Person {
val fullName: String
constructor(firstName: String, familyName: String) : // :는 다른 생성자를 호출할 때 사용
this("$firstName $familyName") // 두 번째 부생성자 호출
constructor(fullName: String) {
this.fullName = fullName
}
}
fun main() {
val person1 = Person("John", "Doe")
println(person1.fullName)
val person2 = Person("John Doe")
println(person2.fullName)
}
- 주생성자와 부생성자를 섞어서 정의할 수 있다.
class Person (fullName: String){
val fullName = fullName
constructor(firstName: String, familyName: String) :
this("$firstName $familyName") // 주생성자 호출
}
fun main() {
val person1 = Person("John", "Doe")
println(person1.fullName)
val person2 = Person("John Doe")
println(person2.fullName)
}
- 파라미터를 프로퍼티로 생성하면, 프로퍼티 초기화 과정을 생략할 수 있다.
class Person (val fullName: String){
constructor(firstName: String, familyName: String) :
this("$firstName $familyName") // 주생성자 호출
}
fun main() {
val person1 = Person("John", "Doe")
println(person1.fullName)
val person2 = Person("John Doe")
println(person2.fullName)
}
멤버 가시성
- 클래스 내부의 멤버 (프로퍼티, 메소드)마다 가시성 설정이 가능하다.
1. public: 멤버를 어디서나 볼 수 있다. (default)
2. internal: 컴파일 모듈 내부에서만 멤버를 볼 수 있다. (함께 컴파일 곳이라면 가능)
3. protected: 멤버가 속한 클래스와 그 하위 클래스에서 볼 수 있다. (상속)
4. private: 멤버가 속한 클래스 내부에서만 볼 수 있다.
class Person(private val firstName: String, private val familyName: String) {
fun fullName() = "$firstName $familyName"
// firstName과 familyName은 클래스 밖에서는 볼 수 없다.
// fullName은 어디서나 볼 수 있다.
}
=> 클래스의 내부 구현을 변경할 때, 클래스 외부의 다른 코드에 영향을 미치지 않게 한다.
=> 무분별한 외부 접근을 방지하여 코드의 안정성을 높인다.
주생성자 가시성
- 주생성자에 public외의 가시성을 주고 싶을 경우 다음과 같이 한다.
class Empty private constructor() {
fun showMe() = println("Empty")
}
// Empty의 유일한 생성자가 private이므로 class 외부에서 인스턴스화 할 수 없음에 유의
내포된 클래스 (nested class)
- 클래스 안에 클래스를 선언할 수 있다.
class Person (val id: Id, val age: Int) { // 인자로 Id 객체를 받는다.
class Id (val firstName: String, val familyName: String) // 내포된 클래스 (클래스 안의 클래스)
fun showMe() = println("${id.firstName} ${id.familyName}, $age")
}
fun main() {
val id = Person.Id("John", "Doe") // 먼저 내부 객체 생성자 호출
val person = Person(id, 25) // 생성한 객체를 다른 생성자의 인자로 전달하며 객체 생성자 호출
person.showMe()
}
내부 클래스 (inner class)
- 내포된 클래스에 inner를 선언하면 내부 클래스(inner class)가 되어 내부 인스턴스가 외부 인스턴스 1개에 소속되게 된다.
1. 내부 인스턴스는 자신이 소속된 외부 인스턴스의 멤버에 접근할 수 있다.
2. 내부 인스턴스는 생성 시 자신이 소속된 외부 인스턴스를 명시해야 한다.
class Person (val firstName: String, val familyName: String) {
inner class Possession(val description: String) {
fun showOwner() = println(fullName())
fun getOwner() = this@Person // 외부 인스턴스를 반환
// this는 속한 클래스의 인스턴스, @Person은 외부 클래스의 이름 명시
}
val myWallet = Possession("Wallet") // this.Possession("Wallet")과 같음
fun fullName() = "$firstName $familyName"
}
fun main() {
val person = Person("John", "Doe")
// 외부 인스턴스 person 생성
val wallet = person.Possession("Wallet")
// 외부 인스턴스 person의 내부 인스턴스로 선언된 wallet (외부 인스턴스 person 명시)
wallet.showOwner() // John Doe
// 내부 인스턴스 wallet이 외부 인스턴스의 멤버(함수)에 접근
val owner = wallet.getOwner()
// owner = person (wallet의 외부 인스턴스)
println(owner.fullName()) // John Doe
}
지역 클래스 (local class)
- 함수 내에 class를 정의할 경우 이를 지역 클래스라 부른다.
- 지역 클래스는 자신을 둘러싼 코드의 멤버에 접근 가능하다.
fun main() {
var x = 1
class Counter {
fun increment() {
x ++
}
}
Counter().increment()
println(x)
}'Study > Kotlin Study' 카테고리의 다른 글
| [Kotlin] 널 가능성 (0) | 2023.09.12 |
|---|---|
| [Kotlin] 함수 (4) | 2023.09.03 |
| [Kotlin] 예외 처리 (0) | 2023.08.25 |
| [Kotlin] 루프 (반복문) (2) | 2023.08.24 |
| [Kotlin] 조건문 (2) | 2023.08.23 |