ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Kotlin] Extension (Function,Property)
    Kotlin/Function 2021. 8. 16. 18:23

    Extension Function 개인참고용

    확장 함수
    
    1. fun 클래스명.확장함수명(파라메터...): 리턴타입{ 구현 }
    nullable한 인스턴스도 받을 수 있는 확장함수의 선언
    fun 클래스명?.확장함수명(파라메터들): 리턴타입{ 구현 } 
    
    2. 조상,자손간의 메서드 오버라이딩시 호출되는 메서드와 다름
    참조변수에 담긴 실제 인스턴스의 메서드가 호출되지 않고
    참조변수의 타입에 해당하는 메서드가 호출됨
    
    3. 확장함수의 시그니쳐에 해당하는 함수가 클래스의 멤버 메서드로 이미 존재하는 경우
    선언한 확장함수가 아닌 멤버 메서드가 호출됨
    다른 시그니쳐로 오버로딩에 해당하는 확장함수를 정의가능
    
    4.  Extension Function의 선언은 Top-level에서 하므로 패키지에 소속
    접근제한자가 어떻게 설정되냐에 따라 다른 파일에서 중복선언 가능여부가 달라짐
    
    5. Top-level선언이므로 Top-level property 처럼 
    다른 패키지에서 확장함수를 사용하려면 import문이 필요함
    
    6. 확장함수의 바디에서 this를 통해 receiver 객체를 사용할 수 있는데
    class의 각 프로퍼티,메서드의 접근제한자에 따라 접근가능한 것들이 다름
    
    7. 확장함수도 Top-level선언이므로 Top-level에 사용할 수 있는 접근제한자를 달 수 있다.
    
    확장 프로퍼티
    
    1. var/val 클래스명.확장프로퍼티명 : 프로퍼티타입 
    	getter - 내부에서 this사용가능
        var인경우 setter - 내부에서 this사용가능
        
    2. 확장프로퍼티는 확장함수와 문법만 다르지 디컴파일된 코드를 보면 확장함수와 동일하게
    구현됨. 확장함수의 경우 하나의 메서드가 추가되는데
    var의 경우 getter,setter메서드가 만들어져야 해서 두개의 메서드가 추가됨

     

    클래스에 메서드를 추가하는 경우 상속을 받아 메서드를 추가하거나, 클래스를 뜯어고쳐야 한다.

    Extension Function을 활용하면 실제로는 기존 클래스의 메서드는 아니지만 마치 클래스의 메서드인 것처럼 사용가능하다. 

    단 멤버 메서드, 프로퍼티처럼 완전히 똑같은 동작을 보이지 않고 차이점이 존재한다.

    Extension Property 또한 Extension Function 과 비슷하다.


    Extension functions

    Kotlin provides the ability to extend a class with new functionality without having to inherit from the class or use design patterns such as Decorator. This is done via special declarations called extensions.

     

    class를 상속받지 않은채로 클래스의 기능을 확장할 수 있다.

    확장함수 선언
    fun 클래스.메서드명(파라메터):리턴타입 { 구현 }

     

    receiver type : 클래스

    receiver object : 클래스의 인스턴스


    Extensions are resolved statically

    실제로 클래스를 변경하는 것이 아니다. 단순히 this를 이용한 dot-notaion으로

    호출할 수 있는 static function을 만드는 것이다.

     

    또한 메서드 호출이 동적이아니라 정적으로 결정되기 때문에, 일반적인 오버라이딩된 메서드의 동작과는 다른 결과를  보인다.

    open class Shape
    class Rectangle : Shape()
    
    fun Shape.getName() = "Shape"
    fun Rectangle.getName() = "Rectangle"
    
    
    fun main() {
    
        val shape: Shape = Shape()
        println(shape.getName())
    
        val rectangle: Shape = Rectangle()
        println(rectangle.getName()) //Shape. Rectangle x
        
    }

    조상 자손간의 메서드 오버라이딩의 동작에 의해 Rectangle이 출력되어야 한다고 생각할 수 있다.

     

    확장함수는 파일명.kt 파일의 class나 function이 아닌 top-level에 선언하였으므로  -> 파일명Kt 클래스 안에 포함되어있다. 디컴파일된 코드를 보면 getName 메서드가 파라메터만 다르게 오버로딩되어있는 것을 볼 수 있다.

    다음과 같이 확장함수로 만들어진 static 메서드 두가지가 있다.

    또한 두 메서드는 메서드 오버로딩이 되어있다.(오버라이딩이 아닌 오버로딩이다!)

     

    인스턴스가 아닌 변수 타입에 해당하는 메서드가 호출된다.


    If a class has a member function, and an extension function is defined which has the same receiver type, the same name, and is applicable to given arguments, the member always wins.

     

    클래스의 멤버메서드와 동일한 signature의 확장함수를 만들때, 항상 멤버메서드가 호출된다.

     

    it's perfectly OK for extension functions to overload member functions that have the same name but a different signature:

    멤버 메서드와 이름만 같지만 다른 시그니쳐인 오버로딩에 해당하는 확장함수를 만드는 것은 가능하다.


    this 키워드

    확장 함수의 구현부에서 receiver object를 this로 사용할 수 있다. this없이 recevier object의 멤버 사용가능

    그러나 확장함수 또한 클래스 외부에서 접근하는 것이므로 private인 멤버는 사용할 수 없다.


    Nullable receiver

    위의 getFullName 확장함수는 non-null변수일때만 사용가능하다.

     

    nullable한 변수를 받을 수 있는 확장함수는 다음과 같이 만들 수 있다.

    클래스명?.확장함수명(파라메터들): 리턴타입{ 구현 }

    확장함수 내부에서 this를 통해 null체크를 진행할 수 있다.


    Extension properties

    property를 확장하는 것은 실제로 클래스에 멤버를 추가하는 것이 아니다. 멤버에 추가된 것 처럼 보이게 한것이다.

    그렇기 때문에 항상 backing field가 만들어지지 않는다.

    확장 프로퍼티는 상태를 가질 수 없기 때문에 초기화를 하는 것이 불가능하다.

    우리가 할 수 있는 것은 setter, getter를 정의하는 것 밖에없다.

    이 setter, getter메서드로 마치 property처럼 동작하게 해주는 것이다.

    (생각해보니 by를 통한 프로퍼티 accesor 위임이랑 문법만 다르지 동작은 비슷한 것 같다)

     

    val 확장 property의 경우 getter를 정의해야하며

    var 확장 property의 경우 getter, setter 모두 정의해야 한다.

     

    Extension Function처럼 getter,setter에서 this를 사용할 수 있다.

    디컴파일된 코드를 보면 확장 함수와 똑같은 형식으로 구현되고 있다.(문법밖에 다른게 없다)

    확장 함수는 하나의 메서드를 만들지만

    확장 프로퍼티가 var변수인 경우 setter,getter두개가 필요해서 두개의 메서드를 만든다는 것 밖에 차이가 없다.


    Companion object extensions

    클래스에 companion object 가 존재하면 companion object의 extension function, extension property를 사용할 수 있다. 

     

    다음과 같이 멤버 메서드의 우선순위가 높은것은 변함이 없었다.

     


    내용 추가 필요

    댓글

Designed by Tistory.