티스토리 뷰

728x90

 


객체 지향(Object Oriented Programming)

• 객체 지향이란 해결해야 할 문제 또는 원하는 바를 "객체"라는 기본 단위를 통해 해결하는 것을 의미.

• 객체란 하나의 역할을 수행하는 묶음 단위.

• 객체들 간의 상호작용을 통해 프로그램을 만듦.

     ex) 고양이 객체, 쥐 객체 생성. 고양이 객체에 할퀴는 기능 구현, 쥐 객체에 도망치는 기능 구현.

• 객체 지향을 잘 하는 법

     - 객체를 어떻게 구성하는 지가 개발을 잘 하는 방법이자 노하우.

     - 개념적, 문법적 지식도 중요하지만 경험이 정말 중요!! -> 하루 아침에 잘 해질 수 없다.

     ex) 축구 게임을 만든다고 가정

          - 개발자 A : 축구 선수, 심판, 경기장, 관중 객체를 생성

          - 개발자 B : 사람, 공, 호루라기, 경기장 객체 생성

          - 개발자 A와 B 중에 누가 더 좋은 코드인가? -> 많은 경험을 통해 판별 가능.

 

클래스(Class)

• 클래스란 객체를 만드는 문법적인 요소.

     - 코틀린은 객체 지향 언어이므로 객체를 만들어내는 이 '클래스'라는 문법이 코틀린에서 매우 중요하다.

• 클래스는 객체를 만들어내는 틀.

     - 클래스로 만들어질 객체가 어떠한 속성, 기능 등을 가질 것일지 작성.

     - 그 후 해당 클래스로 만든 객체는 작성한 속성과 기능을 가짐.

     - 클래스 하나로 여러 객체를 찍어낼 수 있음.

• 객체의 설명서 역할

     - 클래스 안에는 이 클래스로 객체를 만들 때 필요한 재료, 객체가 사용할 수 있는 기능, 속성 등이 적혀있다.

• 클래스는 하나의 자료형으로 사용할 수 있다.

     - 어떤 클래스로 만들어진 객체의 자료형은 해당 클래스가 된다.

• 클래스 이름은 대문자로 시작하는 것이 좋다.

• class 클래스명 {

      내용

  }

class Person { // Person이라는 클래스 생성
    // Person 클래스로 객체를 만들기 위한 규칙 정하는 코드

    // Person 클래스로 만들어낼 객체가 가질 속성, 기능 코드
}
val person: Person = Person() // person 변수를 Person 클래스의 객체로 선언. person의 자료형은 Person이다.

 

프로퍼티 & 메소드

• 객체가 사용할 수 있는 속성은 변수 형태로 저장된다.

     - 이를 프로퍼티(Property)라고 한다.

• 객체가 사용할 수 있는 기능은 함수 형태로 저장된다.

     - 이를 메소드(Method)라고 한다.

• 사람이란 틀을 만들어서 이름, 나이라는 속성이 있고, 걷기라는 기능이 있는 객체를 만든다고 해보자.

     - Person이라는 클래스 안에 name, age라는 프로퍼티, walk()라는 메소드를 생성.

• 객체 생성 시 실행되는 초기화 블록 init이 있다.

     - 코틀린에서는 변수 선언 시 기본적으로 초기값도 같이 할당해주어야 한다.

          ex) val num1 // 오류 발생 : 변수 선언 시 초기값도 할당해야 함.

          ex) val num2 = 10 // 선언 시 초기값도 같이 할당

     - 프로퍼티도 변수이기 때문에 초기값을 할당해주어야 한다.

     - 클래스에서 초기화 과정은 init 블록 안에서 진행 된다.

class Person2 {
    var name: String // 이름이란 속성을 name 프로퍼티로 생성
    var age : Int // 나이란 속성을 age 프로퍼티로 생성

    init {
        // 프로퍼티 초기화
        name = "홍길동"
        age = 20
        
        // 그 외 객체 생성시 필요한 행동
        println("그 외 필요한 행동")
    }

    fun walk(): Unit { // 걷기라는 기능을 walk() 메소드로 생성
        println("걷는다.")
    }
}
val person2: Person2 = Person2() // Person2 클래스를 이용하여 person2 객체 생성
println(person2.name) // 홍길동 출력
println(person2.age) // 20 출력
person2.walk() // 걷는다 출력

 

• 하지만 위의 코드는 객체를 몇 개를 만들어도 name은 홍길동이고 age는 20인 똑같은 객체만 만들어진다.

val person2_2: Person2 = Person2()
val person2_3: Person2 = Person2()
val person2_4: Person2 = Person2()
println(person2_2.name, person2_2.age) // 홍길동20 출력
println(person2_3.name, person2_3.age) // 홍길동20 출력
println(person2_4.name, person2_4.age) // 홍길동20 출력

-> 클래스 외부에서 재료를 받아와서 재료에 맞게 클래스 내부를 만들어야 한다.

 

생성자

1. 주 생성자(Primary Constructor)

• 클래스로 객체를 만들 때 필요한 재료들을 적는 곳.

     - 재료를 인자로 받아 클래스를 구성하는 데에 사용한다.

• 클래스를 선언할 때, 클래스명 옆에 명시

• constructor 키워드를 사용.

class Person3 constructor(personName: String, personAge: Int) { // personName과 personAge라는 재료를 받는다.
    var name: String
    var age: Int

    init {
        name = personName // name 프로퍼티에 생성자가 받은 재료인 personName 저장
        age = personAge // age 프로퍼티에 생성자가 받은 재료인 personAge 저장
    }

    fun walk() {
        println("걷는다.")
    }
}
// 원하는 재료를 넣어 객체 생성
val person3_1: Person3 = Person3("홍길동", 20) // person3_1 객체는 name이 홍길동, age가 20인 객체
val person3_2: Person3 = Person3("고길동", 40) // person3_2 객체는 name이 고길동, age가 40인 객체
val person3_3: Person3 = Person3("김길동", 32) // person3_3 객체는 name이 김길동, age가 32인 객체

val person3_4: Person3 = Person3("이길동") // 오류 발생 : 필요한 재료를 모두 넣지 않았을 경우

 

• constructor 키워드는 생략 가능.

// 객체 생성 시 필요한 재료가 있을 때
class Person4 constructor(personName: String, personAge: Int) { // constructor 키워드 사용
    // ~~ 내용
}

class Person5(personName: String, personAge: Int) { // constructor 키워드 생략
    // ~~ 내용
}

// 객체 생성 시 재료가 필요 없을 때
class Person6 constructor() { // constructor 키워드 사용
    // ~~ 내용
}

class Person7() { // constructor 키워드 생략
    // ~~ 내용
}

class Person8 { // 재료가 필요없으면 ()도 생략 가능
    // ~~ 내용
}

 

• 인자의 기본값을 설정하면 객체 생성 시 재료에 값을 넣지 않아도 기본값으로 할당된다.

class Person9(personName: String = "김아무개", personAge: Int = 30) { // personName, personAge의 기본값 설정
    val name: String
    val age: Int

    init {
        name = personName
        age = personAge
    }
}
val person9_1 = Person9("홍길동", 26) // 필요한 인자 모두 넣음
val person9_2 = Person9("홍길동") // 필요한 인자인 personAge 없음 -> personAge = 30
val person9_3 = Person9() // 필요한 인자인 personName, personAge 없음 -> personName = "김아무개", personAge = 30
println(person9_1.name + person9_1.age) // 홍길동26 출력
println(person9_2.name + person9_2.age) // 홍길동30 출력
println(person9_3.name + person9_3.age) // 김아무개30 출력

 

 

• 프로퍼티 이름과 인자의 이름을 같게 하고 싶을 때는 this 키워드를 사용하여 두 개의 변수를 구분할 수 있다.

     - this 키워드 : 클래스 내부에서 this를 사용하면 해당 클래스, 해당 객체 자기 자신을 의미함.

     - 코틀린에서는 프로퍼티와 인자의 이름을 다르게 하는 것을 권장하지만, 자바에서는 둘의 이름을 같게 한 후 this로 구분하는 스타일이 많이 잡혀있었기 때문에 이렇게도 많이 쓴다.

class Person10(name: String, age: Int) {
    val name: String
    val age: Int

    init {
        this.name = name // this란 이 객체, this.name이란 이 객체의 name, 즉 프로퍼티 name을 뜻함.
        this.age = age // 즉, 프로퍼티 age에 인자로 받아온 age 값을 넣는다는 의미
    }
}
val person10: Person10 = Person10("홍길동", 26)
println(person10.name) // 홍길동 출력
println(person10.age) // 26 출력

 

 

* 클래스 선언 간단하게 생략하는 법

• init의 생략

     - init 블록에서 할 작업이 프로퍼티에 초기값 할당하는 것 밖에 없다면 굳이 init을 사용하지 않고 프로퍼티 생성 시 값 할당을 같이해도 된다.

class Person11 constructor(personName: String, personAge: Int) {
    val name: String = personName // name 프로퍼티 생성 시 초기값 할당도 한 번에 처리
    val age: Int = personAge // age 프로퍼티 생성 시 초기값 할당도 한 번에 처리
}
val person11: Person11 = Person11("홍길동", 26)

• constructor의 생략

class Person12(personName: String, personAge: Int) { // constructor 키워드 생략
    val name: String = personName
    val age: Int = personAge
}
val person12: Person12 = Person12("홍길동", 26)

• 인자 생략

     - 인자를 받아서 프로퍼티에 바로 넣을 것이라면, 아래와 같이 생략할 수 있다.

class Person13(val name: String, val age: Int) { // 인자 생략
}
val person13: Person13 = Person13("홍길동", 26)

 

2. 부 생성자(Secondary Constructor)

• 객체를 만들기 위한 필수 조건은 주 생성자에, 선택할 수 있는 사항은 부 생성자에 적는다.

• 부 생성자는 주 생성자에 적은 필수 조건을 포함하고 있어야 한다.

• 클래스를 생성하는 데에 직접 관여하는 것은 주 생성자이다. -> 부 생성자는 주 생성자에게 객체 생성을 위임해야 한다.

• 부 생성자는 클래스의 본문에 위치한다.

• 부 생성자는 복수 개가 가능하다.

class Person14 constructor(name: String) {
    val name: String
    var age: Int = 0
    var gender: String = "남자"

    init {
        this.name = name
    }

    // 부 생성자는 클래스의 본문에 위치
    // 부 생성자는 필수 조건 name을 반드시 포함
    // 부 생성자는 주 생성자에게 클래스 생성을 위임해야 함.
    // -> 부 생성자가 인자 name, age를 받아서 this(name)으로 넘겨줌
    // -> this가 이 클래스 자신을 나타내므로 this(name)은 곧 Person11(name).
    // -> 즉, name을 주 생성자에게 넘겨주고 생성을 위임.
    // -> 주 생성자에서는 쓰지 않는 age만 본인이 다룸.,
    constructor(name: String, age: Int): this(name) {
       // 부 생성자 블록
       this.age = age
    }

    // 부 생성자는 복수 개가 가능하다.
    constructor(name: String, age: Int, gender: String): this(name) {
        // 부 생성자 블록
        this.age = age
        this.gender = gender
    }
}
val Person14_1 = Person14("홍길동") // 주 생성자만 사용하여 객체 생성
val Person14_2 = Person14() // 오류 발생 : 주 생성자에 필요한 인자가 없으므로
val Person14_3 = Person14("고길동", 50) // 인자가 age까지 있으므로 첫 번째 부 생성자를 사용하여 객체 생성
val Person14_4 = Person14("김길동", 20, "여자") // 인자가 age와 gender까지 있으므로 두 번째 부 생성자를 사용하여 객체 생성
println("" + Person14_1.name + Person14_1.age + Person14_1.gender) // 홍길동0남자 출력
println("" + Person14_3.name + Person14_3.age + Person14_3.gender) // 고길동50남자 출력
println("" + Person14_4.name + Person14_4.age + Person14_4.gender) // 김길동20여자 출력

 

3. 주 생성자와 부 생성자 코드 실행 순서

• 참고 글 : https://slowsure.tistory.com/21

 

[Kotlin] 주 생성자 & 부 생성자 순서

class Person(firstName: String, out: Unit = println("[Primary Constructor] Parameter")) { val fName = println("[Property Person fName] : $firstName") init { println("[init] Person init block") } con..

slowsure.tistory.com

• 주 생성자를 사용하여 객체를 생성했을 때 코드의 순서

     - 주 생성자로 인자를 받아옴 -> 프러퍼티 생성 -> 초기화 함수 실행

• 부 생성자를 사용하여 객체를 생성했을 때 코드의 순서

     - 부 생성자로 인자를 받아옴 -> 주 생성자로 인자를 위임함 -> 프로퍼티 생성 -> 초기화 함수 실행 -> 부 생성자 블록 실행

• 유의점

     - 코틀린에서 변수는 기본적으로 선언 시 초기값이 할당이 되어야 한다.

     - 클래스에서는 프로퍼티 선언 시, 선언과 동시에 초기값을 할당하거나, 초기화 함수를 진행하면서 초기값을 할당해야 한다.

     - 보통 부 생성자에서 받은 값을 프로퍼티에 넣는 작업은 부 생성자 블록에서 많이 하는데, (아래와 같이)

class Person15(name: String) {

    // 생략

    constructor(name: String, age: Int): this(name) {
        // 부 생성자 블록
        this.age = age // 부 생성자에서 받은 age를 프로퍼티인 this.age에 할당
    }
    
    // 생략
    
}

     - 부 생성자 블록의 실행 순서는 맨 마지막이기 때문에, 프로퍼티 생성 후 초기화 함수 실행 전까지 프로퍼티에 초기값이 할당이 되지 않으므로 오류가 발생한다.

     - 따라서 부 생성자 블록에서 할당되는 프로퍼티는 생성과 동시에 초기값을 할당해주어야 한다. (위의 Person14 코드 참고)

 

주 생성자가 없고 부 생성자만 있는 클래스

class Person16 {
    val name: String
    val age: Int

    constructor(name: String, age: Int) {
        this.name = name
        this.age = age
    }
}
val person16_1: Person16 = Person16()
val person16_2: Person16 = Person16("홍길동", 26)

• 주 생성자가 없으면 코틀린에서 자동 생성해준다.

     - 인자를 받지 않고 비어 있는 주 생성자를 자동 생성.

• 주 생성자가 명시되어 있지 않기 때문에 생성 위임도 명시하지 않아도 된다.

• 잘 쓰지 않는 방식이다.

 

클래스로서의 자료형

* 실제로 코틀린에서 사용하는 자료형 Int, String, Boolean 등은 클래스이다.

• 자료형 Int의 선언부에 가보면 Int라는 클래스가 선언되어 있는 것을 알 수 있다.

• 다른 클래스와 마찬가지로 프로퍼티, 메소드 등이 정의되어 있다.

 

 

 

 

 

 

 

이 글은

패스트 캠퍼스 Android 앱 개발의 정석 with Kotlin 올인원 패키지 Online

강의를 듣고 공부한 내용을 바탕으로 작성되었습니다.

 


728x90
댓글
공지사항