[Kotlin] 클래스, 객체, 인터페이스(1)

sw·2022년 1월 17일
0

1. 인터페이스

  • 코틀린 인터페이스는 자바 8의 인터페이스와 비슷한데 추상 메소드뿐 아니라 구현이 있는 메소드도 정의할 수 있다. 단, 필드는 들어갈 수 없다.
interface Clickable{
    fun click()
}

class Button: Clickable{
    override fun click() {
        println("Button Clicked")
    }
}

>>> Button().click()
Button Clicked
  • 자바는 extendsimplements를 사용하지만 코틀린에서는 콜론:으로 클래스 상속과 인터페이스 구현을 모두 처리한다. 자바와 마찬가지로 클래스는 1개만 상속 가능하고 인터페이스는 제한 없이 구현할 수 있다.

  • 자바는 오버라이드할 때 @Override를 생략해도 상관 없지만 코틀린은 override 메소드를 반드시 사용해야 한다.

  • 자바 8에서는 default 키워드를 써줘야 디폴트 구현이 가능하지만 코틀린은 써줄 필요가 없다.

interface Clickable{
    fun click()
    fun showOff() = println("I'm clickable!")
}
// 이 인터페이스를 구현하는 클래스는 click에 대해서는 무조건 구현해야하지만
// showOff의 경우 그대로 사용 or 오버라이드할 수 있다.
  • 이름과 시그니처가 같은 멤버 메소드에 대해 둘 이상의 default 구현이 있는 경우 인터페이스를 구현하는 하위 클래스에서 명시적으로 새로운 구현을 제공해야 한다.

    메소드 시그니처 : 메소드 이름 + 메소드 매개변수 리스트의 조합

interface Clickable{
    fun click()
    fun showOff() = println("I'm clickable")
}

interface Focusable{
    fun showOff() = println("I'm focusable!")
}

class Button: Clickable, Focusable{
    override fun click() {
        println("Button Clicked")
    }

    override fun showOff() {
        super<Clickable>.showOff()
        super<Focusable>.showOff()
    }
    
    // 상위 타입 호출 시 super를 사용한다.
}

자바에서 코틀린의 default 메소드가 있는 인터페이스 구현하기

코틀린은 자바 6과 호환되게 설계됐다. 따라서 자바 8에서 지원하고 있는 default 메소드를 지원하지 않는다. 그래서 디폴트 메소드가 있는 인터페이스를 일반 인터페이스 + 디폴트 메소드 구현이 static 메소드로 들어있는 클래스로 조합해 구현한다. 인터페이스에는 메소드 선언만 들어간다.
그러므로 디폴트 메소드가 포함된 코틀린 인터페이스를 자바 클래스에서 구현하고 싶으면 모든 메소드에 대해 구현해야 한다.
( = 자바에서는 코틀린의 default 메소드 구현에 의존할 수 없다. )



2. open, final, abstract: 기본적으로 final !!!!

  • 코틀린의 기본 클래스와 메소드, 프로퍼티는 기본적으로 final로 상속을 허용하지 않고 있다. 상속을 허용하려면 open 변경자를 앞에 붙여줘야 한다.
open class RichButton: Clickable{
    fun disable(){} // final이므로 하위 클래스에 이 메소드 override 불가
    
    open fun animate(){} // 하위 클래스에 이 메소드 override 가능
    
    override fun click() {} // override한 메소드는 기본적으로 open이다.
    // final override fun click()으로 다시 상속을 막을 수 있다.
}
  • abstract로 추상 클래스를 선언할 수 있고 인스턴스화할 수는 없다. 추상 멤버의 경우는 하위클래스 override해야하기 때문에 항상 열려있다. 그래서 추상 멤버 앞에는 open을 명시할 필요가 없다.
abstract class Animated{
    abstract fun animate() // 추상 함수이기 때문에 항상 open
    
    open fun stopAnimatint(){...} 
    // 추상 함수가 아니지만 원한다면 open으로 오버라이드 허용할 수 있다.
    
    fun animateTwice(){...}
    // final이므로 override 불가
}



3. Visibility Modifier(가시성 변경자)

  • visibility modifer는 코드 기반에 있는 선언에 대해 클래스 외부 접근을 제어한다.

  • 코틀린의 기본 visiblity modiferpublic이다. (모두 공개)

변경자클래스 멤버최상위 선언
public모든 곳에서 볼 수 있다.모든 곳에서 볼 수 있다.
internal같은 모듈 안에서만 볼 수 있다.같은 모듈 안에서만 볼 수 있다.
protected하위 클래스 안에서만 볼 수 있다.(최상위 선언에 적용할 수 없다.)
private같은 클래스 안에서만 볼 수 있다.같은 파일( .kt ) 안에서만 볼 수 있다.

최상위 선언

  • 파일 최상위에 선언되는 클래스, 메소드, 변수를 뜻한다.
  • 자바에서는 최상위 선언에 class만 가능하지만 코틀린에서는 class, method(fun), 변수(val, var) 모두 가능하다.
  • a.kt 파일에 아래와 같이 각각 최상위 선언을 하게되면 class는 패키지 레벨에 최상위 선언으로 그대로 감싸진다. 그리고 method변수는 파일 이름에 해당하는 클래스가 만들어진 후 그 클래스 내부에 변수와 메소드로 들어가게 된다.( 자바와 호환 )
// a.kt
package a

class Example {

}

val ex = 10

fun hi(){
    println("hi")
}

// DeCompile 결과
package a;

public final class Example {}

public final class AKt {
   private static final int ex = 10;

   public static final int getEx() {
      return ex;
   }

   public static final void hi() {
      String var0 = "hi";
      System.out.println(var0);
   }
}
  • 최상위 선언의 기본 visibility modifierpublic이므로 전부 public으로 선언된다. 단, 변수의 경우는 private으로 선언된 다음 get 메소드를 public으로 둔다.
  • 최상위 선언을 private으로 선언하면 그 선언이 들어있는 파일 내부에서만 사용할 수 있기 때문에 하위 시스템의 자세한 구현 사항을 외부에 감추고 싶을 때 유용하다.

최상위 선언에서의 visibility modifier

  • public
    : 모든 곳에서 접근 가능하다.

  • internal
    : 같은 모듈 내부에서만 접근 가능하다. 또 접근하는 변수나 메소드는 internal과 비교했을때 visibility가 같거나 더 높아야한다.(internal, private)
    모듈이란 한 번에 컴파일되는 코틀린 파일들을 의미한다.

internal open class TalkativeButton : Focusable {
    private fun yell() = println("Hey!")
    protected fun whisper() = println("Let's talk!")
}

fun TalkativeButton.giveSpeech(){	// 에러(public 멤버가 internal 타입인 TalkativeButton 노출)
    ...
}
  • private
    : 같은 파일 내부에서만 접근 가능하다.

클래스 멤버의 visibility modifier

  • public
    : 모든 곳에서 접근 가능하다.

  • internal
    : 모듈 내부에서만 접근 가능하다.

// Module1.class
class Module1 {
    internal fun hi() = println("hi")
    fun bye() = println("bye")
}

// Example1.kt(모듈 내부)
fun main(){
    val module = Module1()
    module.hi()
    module.bye()		// 모두 접근 가능
}

// Example2.kt(모듈 외부)
fun main(){
    val module = Module1()
    // module.hi() ---> internal 메소드에는 접근할 수 없다.
    module.bye()
}
  • protected
    : 상속할 때만 접근 가능하다.
// Person.class
open class Person {
    protected fun hello() = println("Hello~")
}

// Example.kt
fun main() {
    val person = Person()
    // person.hello() 접근 불가능!

    val student = Student()
    student.hi()
    // student.hello() 접근 불가능!
}

class Student : Person() {
    fun hi() {
        hello()	// 접근 가능
    }
}
  • private
    : 같은 클래스 내부에서만 접근 가능하다.

코틀린 -> 자바로의 visibility modifier

  • 코틀린의 public, protected, private 변경자는 컴파일된 자바 바이트 코드 안에서도 그대로 유지된다.
    단, 최상위 선언으로 private을 선언했다면 자바에서는 클래스를 private으로 만들 수 없기 때문에 private 클래스를 패키지-전용 클래스로 컴파일한다.

  • internal 같은 경우는 바이트 코드 상 public이 된다. 이 때 코틀린 컴파일러가 internal 멤버의 이름을 나쁘게 바꾼다. 이는 모듈에 속한 클래스를 모듈 외부에서 상속할 때,

  1. 우연히 하위 클래스의 메소드 이름과 internal메소드의 이름이 같아져 오버라이드하는 경우를 방지
  2. 실수로 internal클래스를 모듈 외부에서 사용하는걸 막기 위해서다.
profile
끄적끄적

0개의 댓글