Lesson 3: Classes and objects

11842 단어 androidkotlinandroid

💡 Teach Android Development

구글에서 제공하는 교육자료를 정리하기 위한 포스트입니다.

Android Development Resources for Educators

Classes

  • 클래스는 객체의 청사진 입니다.
  • 클래스는 객체 instances 에서 작동하는 methods가 정의되어 있습니다.

Define and use a class

클래스를 정의하고 객체의 새로운 instance를 생성합니다.

class House {
  val color: String = "white"
  val numberOfWindows: Int = 2
  val isForSale: Boolean = false

  fun updateColor(newColor: String){...}
  ...
}

val myHouse = House()
println(myHouse)

Constructors

생성자가 클래스 해더에 정의될 경우 파라미터를 포함할 수 있습니다.

  • 파라미터 없음
    class A
  • 파라미터 존재
    - var, val 선언이 없으면 생성자 범위 안에서만 사용 가능합니다.
    class B(x: Int)
    - var, val 선언이 있으면 클래스의 모든 instances에서 접근 가능합니다.

Constructor examples

class A

val aa = A()

class B(x: Int)

val bb = B(12) 
println(bb.x) // compiler error unresolved reference

class C(val y: Int)

val cc = C(42)
println(cc.y) // 42

Default parameters

클래스 instances는 기본값을 가질 수 있습니다.

  • 기본값을 사용하여 필요한 생성자 수를 줄입니다.
  • 기본, 필수 매개변수를 혼용할 수 있습니다.
  • 여러 생성자가 필요하지 않아 더 간결합니다.
class Box(val length: Int, val width:Int = 20, val height:Int = 40)
val box1 = Box(100, 20, 40)
val box2 = Box(length = 100)
val box3 = Box(length = 100, width = 20, height = 40)

Primary constructor

클래스 해더안에 기본 생성자를 정의합니다.

class Circle(i: Int) {	
   init {
        ... 
   }
}

위의 방법과 동일한 기능을 합니다.

class Circle {
    constructor(i: Int) {
        ...
    }
}

Initializer block

  • 초기화가 필요한 코드는 init 블록에서 처리할 수 있습니다.
  • 여러개의 init 블록도 허용됩니다.
  • init블록은 기본 생성자의 body가 됩니다.

Initializer block example

class Square(val side: Int) {
    init {
        println(side * 2)
    }
}

val s = Square(10) // 20

Multiple constructors

  • constructor 키워드를 사용해서 secondary constructors 정의할 수 있습니다.
  • Secondary constructors는 this 키워드를 사용해서 기본 생성자를 호출하거나 기본 생성자를 호출하는 또 다른 Secondary constructors를 호출해야 합니다.
  • Secondary constructors의 body는 필수가 아닙니다.

Multiple constructors example

class Circle(val radius:Double) {
    constructor(name:String) : this(1.0)
    constructor(diameter:Int) : this(diameter / 2.0) {
        println("in diameter constructor")
    }
    init {
        println("Area: ${Math.PI * radius * radius}")
    }
}
val c = Circle(3)

Properties

  • val, var를 사용하여 클래스의 Properties을 정의합니다.
  • . 을 사용하여 Properties에 접근합니다.
  • var로 선언된 Properties.로 접근하여 값을 설정할 수 있습니다.

Person class with name property

class Person(var name: String)
fun main() {
    val person = Person("Alex")
    println(person.name)                 Access with .<property name>
    person.name = "Joey"                 Set with .<property name>
    println(person.name)	
}

Custom getters and setters

기본 get/set 사용을 원하지 않을 경우 사용 합니다.

var propertyName: DataType = initialValue
        get() = ...
        set(value) { 
           ...
        } 

Custom getter

class Person(val firstName: String, val lastName:String) {
    val fullName:String
        get() {
            return "$firstName $lastName"
        }
}

val person = Person("John", "Doe")
println(person.fullName) // John Doe

Custom setter

var fullName:String = ""
    get() = "$firstName $lastName"
    set(value) {
        val components = value.split(" ")
        firstName = components[0]
        lastName = components[1]
        field = value
    }

person.fullName = "Jane Smith"

Inheritance

  • 단일 부모 클래스를 상속할 수 있습니다.
  • 각 클래스에는 superclass라고 하는 하나의 부모 클래스가 있습니다.
  • 각 하위 클래스는 superclass가 상속한 항목을 포함하고 superclass의 모든 members를 상속합니다.
  • 하나의 클래스만 상속받을 수 있으므로, 원하는 만큼 implement 할 수 있는interface를 정의할 수 있다.

Interfaces

  • 구현한 모든 클래스가 준수해야 하는 규약을 제공합니다.
  • 매소드명과 속성 이름을 포함할 수 있습니다.
  • 다른 인터페이스에서 파생될 수 있습니다.

Interface example

interface Shape {
    fun computeArea() : Double
}
class Circle(val radius:Double) : Shape {
    override fun computeArea() = Math.PI * radius * radius
}

val c = Circle(3.0)
println(c.computeArea()) // 28.274333882308138

Extending classes

  • 기존 클래스를 핵심으로 사용하는 새로운 클래스를 만듭니다.(subclass)
  • 새로운 클래스를 만들지 않고 클래스에 기능을 추가합니다.(extension functions)

Creating a new class

  • 클래스는 기본적으로 다른 곳에서의 상속을 허용하지 않습니다.
  • 상속을 허용할 경우 open 키워드를 사용합니다.
  • Properties, functionsoverride 키워드를 통해 재정의합니다.
Classes are final by default
class A

class B : A

Error: A is final and cannot be inherited from
Use open keyword
open class C

class D : C()
Overriding
  • 재정의할 수 있는 propertiesmethods에 대해 open을 사용해야 합니다.(그렇지 않을 경우 컴파일 오류 발생)
  • propertiesmethods를 재정의 할때 override 키워드를 사용해야 합니다.
  • override로 표시된 것은 하위 클래스에서 재정의될 수 있습니다.(기본적으로 open, 하위 클래스에서 재정의를 막고 싶으면 final 추가)

Abstract classes

  • 클래스가 abstract로 표시되야 합니다.
  • 인스턴스화할 수 없으며 서브클래스만 가능합니다.
  • 인터페이스와 유사하지만 상태저장 기능이 추가적으로 있습니다.
  • abstract로 표시된 propertiesmethods는 재정의해야 합니다.
  • abstract로 표시되지 않은 propertiesmethods를 포함할 수 있다.
Example abstract classes
abstract class Food {
    abstract val kcal : Int
    abstract val name : String
    fun consume() = println("I'm eating ${name}")
}
class Pizza() : Food() {
    override val kcal = 600
    override val name = "Pizza"
}
fun main() {
    Pizza().consume()    // "I'm eating Pizza"
}

When to use each

  • 광범위한 행동이나 유형을 정의할땐 인터페이스를 고려합니다.
  • 동작이 해당 유형에만 해당될땐 클래스를 고려합니다.
  • 여러 클래스에서 상속해야할 경우 리팩트링을 고려하여 일부 동작을 인터페이스로 분리할 수
    있는지 확인합니다.
  • 일부 propertiesmethods를 하위 클래스에서 재정의되도록 하고 싶을 경우 추상화 클래스를 고려합니다.
  • 하나의 클래스만 extend할 수 있지만 여러 인터페이스를 implement할 수 있습니다.

Extension functions

직접 수정할 수 없는 기존 클래스에 함수를 추가합니다.

  • 구현자가 추가한 것처럼 보입니다.
  • 기존 클래스를 실제로 수정하지 않습니다.
  • private 인스턴스 변수에 접근할 수 없습니다.

Why use extension functions?

  • open되지 않은 클래스에 기능을 추가할 수 있습니다.
  • 소유하지 않은 클래스에 기능을 추가할 수 있습니다.
  • 소유한 클래스의 헬퍼 메소드에서 핵심 API를 분리할 수 있습니다.

    note: 클래스와 같은 파일이나 잘 정의된 함수와 같이 쉽게 검색할 수 있는 위치에 확장함수를 정의합니다.

Extension function example

fun Int.isOdd(): Boolean { return this % 2 == 1 }

3.isOdd() // true

Special classes

Data class

  • 데이터를 저장하기 위한 클래스입니다.
  • 클래스에 data 키워드로 표시합니다.
  • 각 속성에 대해 getter 및 setter(var일 경우)를 생성합니다.
  • toString(), equals(), hashCode(), copy() 메서드 및 다양한 연산자를 생성합니다.

Data class example

data class Player(val name: String, val score: Int)

val firstPlayer = Player("Lauren", 10)
println(firstPlayer) // Player(name=Lauren, score=10)

Pair and Triple

  • 2개나 3개의 데이터를 저장하는 사전 정의된 데이터 클래스입니다.
  • .first, .second, .third를 사용하여 변수에 접근합니다.

Pair and Triple examples

val bookAuthor = Pair("Harry Potter", "J.K. Rowling")
println(bookAuthor) // (Harry Potter, J.K. Rowling)

val bookAuthorYear = Triple("Harry Potter", "J.K. Rowling", 1997)
println(bookAuthorYear) // (Harry Potter, J.K. Rowling, 1997)
println(bookAuthorYear.third) // 1997

Pair to

to를 사용하면 괄호와 마침표를 생략할 수 있습니다.

val bookAuth1 = "Harry Potter".to("J. K. Rowling")
val bookAuth2 = "Harry Potter" to "J. K. Rowling"

MapHashMap과 같은 컬렉션에서도 사용됩니다.

val map = mapOf(1 to "x", 2 to "y", 3 to "zz")

Enum class

지정된 값 집합으로 사용자 정의 데이터 타입입니다.

  • 인스턴스가 여러 상수 값중 하나가 되도록할 때 사용합니다.
  • 상수 값은 기본적으로 사용자에게 표시되지 않습니다.
  • 클래스 앞에 enum 키워드를 사용합니다.

Enum class example

enum class Color(val r: Int, val g: Int, val b: Int) {
   RED(255, 0, 0), GREEN(0, 255, 0), BLUE(0, 0, 255)
}

println("" + Color.RED.r + " " + Color.RED.g + " " + Color.RED.b) // 255 0 0

Object/singleton

  • 클래스의 인스턴스가 하나만 존재하길 원할 때 사용합니다.
  • 클래스 키워드 대신 object 키워드를 사용합니다.

Object/singleton example

object Calculator {
    fun add(n1: Int, n2: Int): Int {
        return n1 + n2
    }
}

println(Calculator.add(2,4)) // 6

Companion objects

  • 클래스의 모든 인스턴스가 이곳에 선언된 변수나 함수를 하나의 인스턴스로 공유합니다.
  • companion 키워드를 사용합니다.
  • ClassName.Property 또는 ClassName.Function 을 통해 참조됩니다.

Companion object example

class PhysicsSystem {
    companion object WorldConstants {
        val gravity = 9.8
        val unit = "metric"
        fun computeForce(mass: Double, accel: Double): Double {
            return mass * accel
        }
    }
}
println(PhysicsSystem.WorldConstants.gravity) // 9.8
println(PhysicsSystem.WorldConstants.computeForce(10.0, 10.0)) // 100.0

Organizing your code

Single file, multiple entities

  • Kotlin은 파일 규칙당 단일 entitiy(class/interface)를 강제하지 않습니다.
  • 같은 파일안의 연관된 구조를 그룹화할 수 있고, 해야합니다.
  • 파일의 길이와 지저분함을 염두에 두어야 합니다.

Packages

  • 조직을 위한 수단 제공
  • 식별자는 일반적으로 소문자 단어로 마침표로 구분합니다.
  • package키워드 다음에 오는 파일에서 주석이 없는 첫 번째 코드 줄에 선언됩니다.
  • org.example.game

Example class hierarchy

Visibility modifiers

  • 가시성 수정자를 사용하여 노출 정보를 제한합니다.
  • public은 외부에서 볼 수 있음을 의미합니다. 클래스의 변수나 메소드를 포함하여 모든 것이 기본적으로 공개됩니다.
  • private은 오직 해당 클래스(또는 함수로 작업하는 경우 소스 파일)에서만 볼 수 있음을 의미합니다.
  • protected는 private와 동일하지만, 모든 subclass에서 볼 수 있습니다.

좋은 웹페이지 즐겨찾기