[Kotlin 객체지향 (1)] 클래스, 패키지, 모듈, 접근 제한자, 상속
Language/Kotlin

[Kotlin 객체지향 (1)] 클래스, 패키지, 모듈, 접근 제한자, 상속

728x90
반응형

객체지향 프로그래밍 개요

  • 객체 지향 프로그래밍이란 프로그램에서 사용되는 여러 데이터나 기능을 객체로 묶어서 관리하는 프로그래밍 기법입니다.
  • 객체는 매개체 하나에 대한 정보와 기능을 담고 있는 프로그램 요소입니다.
  • 데이터만 관리하는 것이 아니고 기능까지 관리하는 것이 객체입니다.
  • 자바에서는 모든 코드들을 클래스 내부에 만들어야하기 때문에 어떤 매개체의 데이터를 관리하는 목적이 아닌, 특정 기능을 구현하는 목적으로 코드를 작성하더라도 무조건 클래스를 만들었어야 했습니다.
  • 그러나 코틀린은 함수형 프로그래밍 즉 함수형 코드들을 지원하기 때문에 코틀린에서의 객체는 특정 매개체 하나에 대한 데이터와 그 데이터를 처리할 기능들을 위한 목적으로만 사용하게 됩니다. 

객체의 특징

  • 매개체 하나의 정보를 관리하기 위해서는 객체 하나가 필요하며 관리하고자 하는 매개체의 수만큼 객체를 생성해야 한다.
  • 객체는 독립적으로 관리되며 서로에 대해 관여하지 않는다.

클래스

  • Kotlin에서 객체는 자바와 동일하게 클래스를 설계하고 이를 통해 생성됩니다. 
  • 클래스에 정의한 변수와 메서드(함수)의 구조대로 객체가 생성되며 같은 형태의 객체가 필요하다면 같은 클래스로 객체들을 생성하면 됩니다. 
  • class 클래스명 {
    }


생성자

  • 클래스를 통해 객체를 생성할 때 자동으로 수행될 코드를 작성하는 곳이다.
  • 메서드와 비슷해 보이지만 반환 타입이 없어 메서드라고 부르지 않는다.
  • 생성자의 역할은 클래스가 가지고 있는 변수의 값을 초기화 하는데 주로 이동된다.
  • constructor를 이용하여 생성자를 정의할 수 있다.
  • 생성자는 매개변수의 개수나 자료형을 달리하여 여러 개를 만들어 사용할 수 있다.
class MyClass{
    var v1:Int = 0
    var v2:Int = 0

    constructor(){
        println("매개 변수가 없는 생성자")
    }

    constructor(a1:Int, a2:Int){
        println("매개 변수가 두 개인 생성자")
        v1 = a1
        v2 = a2
    }
}

cf) init 코드블록

  • Kotlin은 클래스에 init 코드 블록을 만들어 주면 객체 생성 시 자동으로 처리되는 코드를 만들 수 있다.
class MyClass{
    
    init{
        println("객체가 생성되면 자동으로 동작되는 부분입니다")
    }
}

기본 생성자(주 생성자)

  • 클래스를 정의할 때 클래스 이름 우측에 정의하는 생성자
  • constructor 는 생략할 수 있음
class MyClass1 constructor (a1:Int, a2:Int)
class MyClass2(a1:Int, a2:Int)

 

  • 기본생성자의 매개변수에 val 혹은 var키워드를 붙이면 매개 변수가 멤버 변수로 자동 등록된다.
class MyClass1 constructor (var a1:Int, val a2:Int)
class MyClass2(var a1:Int, val a2:Int)
main(){

    val myObj = MyClass1(100, 200)
    
    println("myObj.a1 : ${myObj.a1}")
    println("myObj.a2 : ${myObj.a2}")

}

수행결과 : 100, 200 각각 프린트됨

보조 생성자(부생성자)

  • 보조생성자는 val, var키워드 사용 불가능
class MyClass{
        var v1 :Int = 0;
        var v2 :Int = 0;
        
        constructor(a1:Int, a2:Int){  // 보조 생성자인 경우 var val 못씀
                v1 = a1
                v2 = a2
         }
}

 

생성자 확장(기본+보조 생성자 같이 있는 경우) 

  • 주생성자가 있는경우 보조생성자를 호출할 때 무조건 주 생성자를 호출해야 함 (this로 호출 가능~!)
class MyClass(var a1:Int, val a2:Int){

    constructor(a1:Int) : this(a1, 100){// 주생성자가 있는 경우 보조생성자는 무조건 주생성자를 호출해야 함 
        println("보조 생성자 호출")
    }
}
class MyClass constructor {
        var v1 :Int = 0;
        var v2 :Int = 0;
        
        constructor(a1:Int): this(a1, 100){    // 주생성자가 있는 경우 보조생성자는 무조건 주생성자를 호출해야 함 
                v1 = a1
                v2 = a2
         }
}

 

주생성자, 보조생성자 ,init 수행 순서

 

class MyClass (var a1:Int, val a2:Int){

    init{
        println("init 코드 수행")
        println("a1 : $a1")
        println("a2 : $a2")
    }

    constructor(a1:Int) : this(a1, 100){
        println("보조 생성자 호출")
    }
}



// 호출!!
main(){
    val obj = MyClass(100)
}

 

수행결과: 

 

1) 주생성자     ->     2) init      ->      3) 보조생성자

 

 

 

상속

  • 중복된 요소들을 갖고 있는 클래스들이 있을 때 상위 부모 클래스를 상속받아서 사용할 수 있습니다.
  • 클래스를 설계할 때 다른 클래스에 정의한 요소를 그대로 물려받는 것을 상속이라고 부른다.
  • 그래서 어떤 부분을 수정할 때 부모 클래스만 수정하면 자식 클래스
  • Java의 경우 클래스 default는 부모 클래스(상속가능)이고, 상속받지 못하게 하려면 final 키워드를 사용해야 된다. 반면 코틀린의 경우 상속가능한 클래스인 부모클래스는 open 키워드를 사용해야 한다. open 키워드를 사용하지 않으면 자바 코드로 변경될 때 final 키워드가 붙는다.
open class SuperClass1{
    var superMember1 = 100

    fun superMethod1(){
        println("SuperClass1의 메서드 입니다")
    }
}
class SubClass1 : SuperClass1(){
    val subMember1 = 200
    
    fun subMember1(){
        println("SubClass1의 메서드 입니다")
    }
}
fun main() {
    val s1 = SubClass1()
    println("s1.subMember1 : ${s1.subMember1}")
    s1.subMember1()

    println("s1.superMember1 : ${s1.superMember1}")
    s1.superMethod1()
}

 

상속 방법 2가지

 

부모클래스

open class SuperClass2(val a1:Int)

자식클래스 (상속방법 1)

class SubClass2 : SuperClass2(100)

 

자식클래스 (상속방법2)

class SubClass3 : SuperClass2{

    constructor() : super(100)
}

 

 

패키지

  • 소프트웨어를 개발하다 보면 클래스도 많이 만들게 되고 kt 파일도 많이 만들게 되는데, 점점 파일이 많아져 관리가 불편하고 배포가 힘들어집니다. 이때 특정 기준을 세워 파일을 폴더별로 나누어 관리하면 파일 관리가 용이해집니다.
  • Kotlin에서 kt 파일들을 폴더 별로 나누어 관리하는 개념을 패키지라고 부른다.

패키지는 폴더로 구분하면 됩니다.

패키지 내에 있는 파일들은 상단에 패키지를 명시해야 합니다.

패키지 내에 있는 클래스 등을 사용할 때는 반드시 패키명을 명시해야 한다.

import를 사용해 패키지를 명시하면 코드 내에서 패키지 명을 생략할 수 있다.

모듈 

  • kt 파일들을 모아 관리하는 개념이 패키지라면 모듈을 패키지를 모아 관리하는 개념으로 패키지가 많아지면 관리하기가 어려워질 수 있는데 이때 모듈로 묶어서 사용합니다.
  • 00모듈을 java, 다른 모듈은 kotlin 이렇게 다른 종류의 모듈을 만들어서 사용할 수 있습니다.

  • 모듈은 같은 프로젝트에 있을 수도 있고, 다른 프로젝트에 있을수도 있는데 이때 꼭 모듈을 등록해주어야 합니다.

접근 제한자 

  • 객체가 가지고 있는 변수는 . 연산자를 통해 자유롭게 접근이 가능합니다. 그러나 만약 변수에 담기는 값이 어떠한 조건이 있을 경우 외부에서 자유롭게 접근할 수 있다면 엉뚱한 값이 저장될 가능성이 있게 됩니다. 따라서 변수나 메서드의 접근 권한을 설정할 수 있는 접근 제한자를 제공하고 있으며 클래스를 설계하는 개발자가 각 변수나 메서드의 접근 권한을 설정해 오동작 하는 것을 사전에 막을 수 있게 합니다.
  • Java 에서는..... private(해당 클래스 내에서만 접근가능)/ default(해당 패키지 내에서만 접근가능)/protected(해당 패키지내의 클래스, 해당 클래스를 상속받은 외부 패키지의 클래스에서만 접근가능)/ public(어디에서든 접근가능) /접근제어자를 별도로 설정하지 않으면 default 접근제어자
  • Kotlin에서는 클래스의 정의한 모든 변수는 Java코드로 변경될 때 private?가 설정 됩니다. (getter/setter자동추가)
  • 접근 제한자의 종류에 따라 Java 코드로 변경될 때 getter 메서드 추가 여부가 결정된다.

클래스 접근 제한자

  • private : 외부에서 객체를 생성할 수 없다.
  • public : 외부에서 객체를 생성할 수 있다(기본).
  • protected : 클래스에 지정 불가
  • internal  : 모듈 같을 경우에만 객체를 생성할 수 있다.

변수/메서드 접근 제한자

  • 변수와 메서드는 동일하게 적용된다.
  • private : 외부에서 접근할 수 없다.
  • public : 외부에서 접근이 자유롭다(기본).
  • protected : 상속관계일 경우에만 접근이 가능하다.
  • internal  : 모듈 같을 경우에만 접근이 가능하다.

 


Overriding

  • Kotlin의 모든 객체는 부모 클래스형 참조 변수에 담을 수 있다.
  • 부모 클래스형 참조 변수를 사용하면 부모 클래스에 정의되어 있는 맴버만 사용이 가능하다.

Overrriding

  • 부모 클래스가 가지고 있는 메서드를 자식 클래스에서 재 정의하는 개념이다.
  • 부모가 가지고 있는 메서드의 이름, 매개 변수 형태 모두 동일 해야 한다.
  • 만약 객체가 부모형 참조변수에 담겨 있다면 부모 영역에 정의한 맴버만 사용할 수 있다.
  • 만약 부모의 메서드를 자식에서 Overriding을 했다면 부모형 참조 변수를 통해 자식의 메서드를 호출 할 수 있다.
  • 이는 이벤트 처리 방식에서 사건이 발생했을 경우 개발자가 만든 메서드를 호출하기 위해 사용하는 매우 중요한 개념이다.

super

  • 메서드를 Overriding한 경우 부모의 메서드를 호출하고자 한다면 super 키워드를 사용한다.
  • super는 상속관계에서 부모를 의미한다.

Any

  • Kotlin에서 사용하는 모든 클래스의 부모 클래스이다.
  • Kotlin은 클래스를 작성할 때 상속받지 않는다면 자동으로 Any 클래스를 상속받는다.
  • Any 클래스에는 모든 객체가 가지고 있어야할 메서드가 제공되고 있으며 이 메서드들을 Overriding 하여 각 클래스의 성격에 맞게 재 구현하여 사용할 수 있다.

this와 super

this

  • 객체 자기 자신을 지칭한다.
  • 멤버 변수와 메서드 내부의 변수를 구분할 때 사용한다.
  • 멤버 메서드와 메서드 내부의 메서드를 구분할 때 사용한다.
  • 생성자에서 다른 생성자를 호출할 때 사용한다.

super

  • 부모 영역을 지칭한다.
  • 멤버 변수와 상속받은 멤버 변수를 구분할 때 사용한다.
  • Overriding한 메서드와 부모의 메서드를 구분할 때 사용한다.
  • 부모의 생성자를 호출할 때 사용한다.

 

728x90
반응형