본문 바로가기
프로그래밍/Kotlin

[Kotlin 기초 2] Objects (2)

by 채연2 2023. 2. 9.

 

2023.02.09 - [프로그래밍/Kotlin] - [Kotlin 기초 2] Objects (1) 

 

Contents

     

     

    Objects

    Access Modifiers

    가시성을 제어하기 위해 Kotlin 및 일부 다른 언어는 접근 제한자를 제공한다. 라이브러리 작성자는 public, private, protected, internal 제한자를 사용하여 클라이언트 프로그래머가 접근할 수 있는 항목과 접근할 수 없는 항목을 결정한다.

    • private : 숨겨져 있으며 동일한 클래스의 다른 멤버에서만 접근 가능하다. 정의를 변경하거나 제거하더라도 클라이언트 프로그래머에게 직접적인 영향을 미치지는 않는다.
    • public : 클라이언트 프로그래머가 접근할 수 있으므로 해당 정의를 변경하면 클라이언트 코드에 직접적인 영향을 미친다. 제한자를 제공하지 않으면 정의가 자동으로 공개된다.
    private var index = 0                      // [1]
    private class Animal(val name: String)     // [2]
    
    private fun recordAnimal(animal: Animal) { // [3]
       Log.e("cylog", "Animal #$index: ${animal.name}")
       index++
    }
    
    fun recordAnimals() {
       recordAnimal(Animal("Tiger"))
       recordAnimal(Animal("Antelope"))
    }
    
    fun recordAnimalsCount() {
       Log.e("cylog", "$index animals are here!")
    }
    
    fun test() {
       recordAnimals()
       recordAnimalsCount()
    }

     

    같은 파일 내의 다른 함수 및 클래스에서 private 최상위 속성 [1], 클래스 [2], 함수 [3]에 접근 할 수 있다. Kotlin은 다른 파일 내에서 private 최상위 속성에 접근 하는 것을 방지하여 파일에서 private임을 알려준다.

     

    Privacy는 클래스 멤버들에게 가장 일반적으로 사용된다.

     

    class Cookie(
       private var isReady: Boolean // [1]
    ) {
       private fun crumble() =      // [2]
          Log.e("cylog", "crumble")
          
       public fun bite() =          // [3]
          Log.e("cylog", "bite")
          
       fun eat() { // [4]
          isReady = true            // [5]
          crumble()
          bite()
       }
    }
    
    fun test() {
       val x = Cookie(false)
       x.bite()
       // x.isReady
       // x.crumble()
       x.eat()
    }


    [1] : 클래스 외부에서 접근할 수 없음
    [2] : private 멤버 함수
    [3] : 누구나 접근 가능한 멤버 함수
    [4] 접근 제한자 없음 = 공개
    [5] : 같은 클래스 멤버만 private 멤버에 접근 가능

     

    private 키워드는 해당 클래스의 다른 멤버를 제외하고는 아무도 해당 멤버에 접근할 수 없음을 의미한다. 다른 클래스는 private 멤버에 접근할 수 없으므로 클래스를 자신과 공동 작업자로부터 분리하는 것과 같다. private를 사용하면 동일 패키지 내 다른 클래스에 영향을 미치는지 걱정하지 않고 해당 멤버를 자유롭게 변경 가능하다.

     

    클래스의 헬퍼 함수인 멤버 함수는 패키지의 다른 곳에서 실수로 사용하지 않도록 private로 만들어 해당 함수를 변경하거나 제거하지 못하도록 할 수 있다. 클래스 내부의 private 속성에 대해서도 마찬가지이다.

     

    하지만 객체에 대한 참조가 클래스 내에서 private라고 해서 다른 객체가 동일한 객체에 대한 public 참조를 가질 수 없다는 의미는 아니다. 즉, A 클래스 내 private 속성 멤버에 대해서 A를 참조하는 객체 A1, A2 둘 다 private 속성 멤버에 접근 가능하다는 의미이다.

     

    class Counter(var start: Int) {
       fun increment() {
          start += 1
       }
       
       override fun toString() = start.toString()
    }
    
    class CounterHolder(counter: Counter) {
       private val ctr = counter
      
       override fun toString() = "CounterHolder: " + ctr
    }
    
    fun test() {
       val c = Counter(11)                  // [1]
       val ch = CounterHolder(c)            // [2]
       Log.e("cylog", "ch : $ch")
       
       c.increment()                        // [3]
       Log.e("cylog", "ch : $ch")
       
       val ch2 = CounterHolder(Counter(9))  // [4]
       Log.e("cylog", "ch2 : $ch2")
    }
    [2] : CounterHolder 생성자에 대한 매개변수로 [1]에서의 c를 전달 (생성된 CounterHolder가 c를 참조하는 것과 동일한 Counter Object를 참조한다는 것을 의미)
    [3] : ch 생성 시 매개변수로 c를 전달하여도 c를 통해 Counter 객체를 조작할 수 있음
    [4] : Counter(9)는 다른 참조가 없으므로 ch2 이외에 어떤 것도 접근 및 수정 불가

     

    Modules

    프로그램은 하나 이상의 모듈로 나누는 것이 좋다. 모듈은 코드 베이스의 논리적으로 독립된 부분이다. 프로젝트를 모듈로 나누는 방법은 빌드 시스템에 따라 다르다.

     

    internal 키워드는 정의된 모듈 내부에서만 접근 가능하다. internal은 private와 public 사이의 위치하며 private가 너무 제한적이지만 요소가 publicI의 일부가 되는 것을 원하지 않을 때 사용된다.

     

    module은 더 높은 수준의 개념이다. 라이브러리는 종종 여러 패키지로 구성된 단일 모듈이므로 internal 요소들은 라이브러리 내에서 사용할 수 있지만 해당 라이브러리의 소비자는 접근할 수 없다.

     

    Packages

    import packagename.ClassName
    import packagename.functionName
    import packagename.propertyName

    Package는 연관된 코드의 집합, 모임이다. 각 패키지는 일반적으로 특정 문제를 해결하도록 설계되었으며 종종 여러 함수와 클래스를 포함한다. 예를 들어 kotlin.math 라이브러리에서 수학 상수와 함수를 가져올 수 있다.

     

    import kotlin.math.PI
    import kotlin.math.cos
    
    fun test() {
       Log.e("cylog", "1 : $PI")
       Log.e("cylog", "2 : ${cos(PI)}")
       Log.e("cylog", "3 : ${cos(2 * PI)}")
    }

     

    이름이 같은 클래스나 함수가 포함된 여러 외부 라이브러리를 사용하려는 경우, as 키워드를 사용하면 가져오는 중에 이름을 변경할 수 있다. as는 라이브러리 이름이 잘못 선택되었거나 지나치게 긴 경우에 유용하다.

     

    import kotlin.math.PI as circleRatio
    import kotlin.math.cos as cosine
    
    fun test() {
       Log.e("cylog", "1 : $circleRatio")
       Log.e("cylog", "2 : ${cosine(circleRatio)}")
       Log.e("cylog", "3 : ${cosine(2 * circleRatio)}")
    }

     

    패키지에서 모든 항목을 가져오려면 별 문자(*)를 사용하면 된다.

     

    import kotlin.math.*
    
    fun test() {
       Log.e("cylog", "1 : $E")
       Log.e("cylog", "2 : ${E.roundToInt()}")
       Log.e("cylog", "3 : ${E.toInt()}")
    }

    코드를 재사용하려면 package 키워드를 사용하여 패키지를 생성하면 된다. 패키지 명령문은 파일에서 주석이 아닌 첫 번째 명령문이어야 한다. package 다음에는 패키지 이름이 오며 규칙에 따라 모두 소문자로 작성한다.

     

    파일 이름이 클래스 이름과 같아야 하는 Java와는 달리 소스 코드 파일의 이름은 원하는 대로 지정 가능하다. Kotlin에서는 패키지 이름을 선택할 수 있지만 패키지 이름이 패키지 파일이 있는 디렉토리 이름과 동일한 것이 좋은 스타일로 간주된다.

     

    ※ Android Studio의 경우 AndroidManifest.xml 파일의 activity name 속성 값도 같이 변경해 주어야 한다.

     

    package pythagorean
    
    import kotlin.math.sqrt
    
    class RightTriangle(
       val a: Double,
       val b: Double
    ) {
       fun hypotenuse() = sqrt(a * a + b * b)
       fun area() = a * b / 2
    }
       
    fun test() {
       val rt = RightTriangle(3.0, 4.0)
       Log.e("cylog", "${rt.hypotenuse()}")
       Log.e("cylog", "${rt.area()}")
    }
    <?xml version="1.0" encoding="utf-8"?>
    <manifest>
       <application>
          <activity android:name="pythagorean.MainActivity">
          </activity>
       </application>
    </manifest>

     

     

     

    320x100

    '프로그래밍 > Kotlin' 카테고리의 다른 글

    Kotlin 배우기 (1)  (0) 2024.02.01
    [Kotlin 기초 2] Objects (3)  (9) 2023.02.17
    [Kotlin 기초 2] Objects (1)  (4) 2023.02.09
    [Kotlin 기초 1] 기본 구문 (3)  (4) 2023.02.07
    [Kotlin 기초 1] 기본 구문 (2)  (7) 2023.02.07

    댓글