Post

[안드로이드] Ch4. 코틀린 객체지향 프로그래밍

※ 본 포스팅은 “깡샘의 안드로이드 앱 프로그래밍 with 코틀린” 을 참고하여 작성하였습니다.

04-1. 클래스와 생성자

  • 클래스 선언

    • [형식] class User {}

    • 클래스의 멤버: 생성자, 변수, 함수, 클래스

    • 생성자

      1
      2
      3
      4
      5
      
      class User{
      		constructor(name: String){
      				this.name= name
      		}
      }
      
    • 클래스: 클래스 안에 다른 클래스를 선언할 수 있음

      1
      2
      3
      
      class User{
      		class SomeClass {}
      }
      
  • 주 생성자

    • Explanation

      • 코틀린 클래스의 생성자는 주 생성자와 보조 생성자로 구분된다.
      • 주 생성자 선언은 필수는 아니지만 한 클래스에 하나만 가능함
      • 주 생성자 선언을 하지 않으면 컴파일러가 매개변수가 없는 주 생성자를 자동으로 추가
    • 주 생성자의 본문- init 영역

      • init 키워드로 주 생성자의 본문을 구현할 수 있음

      • 객체를 생성하면 자동으로 실행됨

      • (나중에) 보조 생성자로 객체를 생성할 때도 init 으로 실행 가능

      • 주 생성자로 받는 매개변수는 init에만 적용되는 지역 변수이므로,

        → 클래스 내의 다른 함수에서도 매개변수를 이용하고 싶다면 클래스 멤버 변수를 선언해야 함

        → 또는 그냥 주 생성자의 매개변수에 var이나 val 키워드를 선언하면 바로 클래스 멤버 변수 이용 가능(원래 함수는 매개변수 선언 시 var이나 val 키워드를 추가할 수 없음)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      
      class User(val name: String, val count: Int){
      		init{
      				println("i am init")
      		}
      		fun someFun(){
      				println("name: $name, count: $count")
      		}
      }
          
      fun main(){
      		val user= User("kkang", 10)
      		user.someFun()
      }
      // 실행 결과:
      // i am unit
      // name: kkang, count: 10
      
  • 보조 생성자

    • Explanation

      • 클래스의 본문에 constructor 키워드로 선언하는 함수
      • 객체를 생성하면 자동으로 실행됨
    • 보조 생성자에 주 생성자 연결

      클래스에서 두 생성자를 모두 선언할 시에는 반드시 생성자끼리 연결해주어야 함

      • 보조 생성자(1개)에서 주 생성자 호출

        1
        2
        3
        4
        5
        6
        7
        8
        
        class User(name: String){
        		constructor(name: String, count: Int): this(name){
        				(...)
        		}
        }
        fun main(){
        		val user= User("kkang", 10)
        }
        
      • 보조 생성자(여러개)에서 주 생성자 호출

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        
        class User(name: String){
        		init{
        				(...)
        		}
        		constructor(name: String, count: Int): this(name){
        				(...)
        		}
        		constructor(name: String, count: Int, email: String): this(name, count){
        				(...)
        		}
        }
        fun main(){
        		val user= User("kkang", 10, "a@a.com")
        }
        

04-2. 클래스를 재사용하는 상속

  • 상속과 생성자

    • 클래스 상속 형식: 상위 클래스에는 open 키워드 필수**

      1
      2
      3
      4
      5
      6
      
      open class Super{
          
      }
      class Sub: Super(){
          
      }
      
    • 하위 클래스에서의 상위 클래스 생성자 호출

      • 하위 클래스에 보조 생성자가 없는 경우

        1
        2
        3
        4
        5
        6
        
        open class Super(name: String){
              
        }
        class Sub(name: String): Super(name){
              
        }
        
      • 하위 클래스에 보조 생성자가 있는 경우

        1
        2
        3
        4
        5
        6
        7
        8
        
        open class Super(name: String){
              
        }
        class Sub(name: String){
        		constructor(name: String): super(name){
        				// 보조 생성자에서는 상위 클래스의 맨 앞이 소문자
        		}
        }
        
  • 오버라이딩- 재정의

    • Explanation

      • 상위 클래스에 선언된 변수나 함수를 같은 이름으로 하위 클래스에서 다시 선언하는 것
      • 상위 클래스는 변수나 함수 앞에 open 키워드를 작성해야 함
      • 하위 클래스는 변수나 함수 앞에 override 키워드를 작성해야 함
    • 예시

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      
      open class Super{
      		open var someData= 10
      		open fun someFun(){
      				println("i am super class function: $someData")
      		}
      }
      class Sub: Super(){
      		override var someData= 20
      		override fun someFun(){
      				println("i am sub class function: $someData")
      		}
      }
          
      fun main(){
      		val obj= Sub()
      		obj.someFun()
      }
      // 실행 결과: i am sub class function: 20
      
  • 접근 제한자

    접근 제한자최상위에서 이용클래스 멤버에서 이용
    public모든 파일에서 가능모든 클래스에서 가능
    internal같은 모듈 내에서 가능같은 모듈 내에서 가능
    protected사용 불가상속 관계의 하위 클래스에서만 가능
    private파일 내부에서만 이용클래스 내부에서만 이용
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    open class Super{
    		var publicData= 10
    		protected var protectedData= 20
    		private var privateData= 30
    }
    class Sub: Super(){
    		fun subFun(){
    				publicData++ // 성공
    				protectedData++ // 성공
    				privateData++ // 오류
    		}
    }
    fun main(){
    		val obj= Super()
    		obj.publicData++ // 성공
    		obj.protectedData++ // 오류
    		obj.privateData++ // 오류
    }
    

04-3. 코틀린의 클래스 종류

  • 데이터 클래스

    • Explanation

      • data 키워드로 선언
      • 자주 사용하는 데이터를 객체로 묶어줌
      • 데이터 클래스는 VO 클래스를 편리하게 이용할 수 있게 해줌
    • [형식] data class DataClass(val name: String, val email: String, val age: Int)

    • VO 클래스- equals(): 객체의 데이터가 같은지 비교

      • 멤버 변수 값이 같은 일반 클래스의 객체를 비교하면 결괏값은 false
      • 멤버 변수 값이 같은 데이터 클래스의 객체를 비교하면 결괏값은 true

      ⇒ 주 생성자에 선언한 멤버 변수의 데이터만 비교 대상으로 삼음

    • VO 클래스- toString()

      • 일반 클래스의 객체.toString()의 출력 값은 의미있는 데이터가 아님
      • 데이터 클래스의 객체.toString()의 출력 값은 객체가 포함하는 멤버 변수의 데이터를 출력

      ⇒ 주 생성자의 매개변수에 선언된 데이터만 출력 대상

  • 오브젝트 클래스

    • Explanation

      • object 키워드로 선언
      • 익명 클래스를 만들 목적으로 사용
      • 클래스 이름이 없으므로 클래스를 선언하면서 동시에 객체를 생성해야 함
    • [형식] 객체 이름= object: 타입 { … }

      • object는 콜론(:) 뒤에 타입을 명시하여 선언해야 함
      • 타입을 명시하지 않으면 객체는 Any 타입이 되고,
      • Any 타입에 선언된 멤버가 없으므로 오류
    • 사용 예시

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      
      open class Super{
      		open var data= 10
      		open fun some(){
      				println("i am super some(): $data")
      		}
      }
          
      val obj= object: Super(){
      		override var data= 20
      		override fun some(){
      				println("i am object some(): $data")
      		}
      }
          
      fun main(){
      		obj.data= 30
      		obj.some()
      }
      // 실행 결과: i am object some(): 30
      
  • 캠패니언 클래스

    • Explanation

      • 클래스 내부에 companion object { … } 의 형식으로 선언
      • 객체를 생성하지 않고서도 클래스 이름으로 특정 멤버를 이용할 수 있음
    • 예시- companion object {} 를 감싸는 클래스 이름(MyClass)으로 멤버에 접근할 수 있음

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      
      class MyClass{
      		companion object{
      				var data= 10
      				fun some(){
      						println(data)
      				}
      		}
      }
      fun main(){
      		MyClass.data= 20 // 성공
      		MyClass.some() // 성공
      }
      

정리

  • 클래스의 생성자는 주 생성자와 보조 생성자로 구분된다.
  • 주 생성자의 매개변수에 var이나 val 키워드를 추가하면 클래스의 멤버 변수가 된다.
  • 클래스가 상속을 허용하려면 open 키워드를 추가해서 선언해야 한다.
  • 멤버 변수나 함수를 재정의하려면 override 키워드를 추가해서 선언하여 구현해야 한다.
  • 접근 제한자: public, internal, protected, private
  • data 키워드로 선언한 클래스의 equal() 은 객체 자체가 아니라 객체의 데이터를 비교한다.
  • data 키워드로 선언한 클래스의 toString()은 객체의 주 생성자의 멤버 데이터들의 값을 출력한다.
  • object 키워드로 익명 클래스를 정의한다.
  • companion 키워드로 객체를 생성하지 않고 바로 클래스의 멤버에 접근한다.
This post is licensed under CC BY 4.0 by the author.