Kotlin : 인터페이스… 생성자가 없습니다


138

Java 코드 중 일부를 Kotlin으로 변환 중이며 Kotlin 코드에 정의 된 인터페이스를 인스턴스화하는 방법을 잘 이해하지 못합니다. 예를 들어 인터페이스 (Java 코드로 정의)가 있습니다.

public interface MyInterface {
    void onLocationMeasured(Location location);
}

그런 다음 Kotlin 코드 에서이 인터페이스를 인스턴스화합니다.

val myObj = new MyInterface { Log.d("...", "...") }

잘 작동합니다. 그러나 MyInterface를 Kotlin으로 변환 할 때 :

interface MyInterface {
    fun onLocationMeasured(location: Location)
}

오류 메시지가 나타납니다. Interface MyListener does not have constructors인스턴스화하려고하면 구문 이외의 다른 변경 사항이없는 것 같습니다. Kotlin에서 인터페이스의 작동 방식을 이해하지 못합니까?

답변:


225

Java 코드는 SAM 변환 (람다를 단일 추상 메소드를 사용하여 인터페이스로 자동 변환)에 의존합니다. Kotlin에 정의 된 인터페이스 에는 현재 SAM 변환이 지원되지 않습니다 . 대신 인터페이스를 구현하는 익명 객체를 정의해야합니다.

val obj = object : MyInterface {
    override fun onLocationMeasured(location: Location) { ... }
}

14
많은 감사합니다. 게시 한 링크에서 Location -> Unit가능한 경우 단일 방법 인터페이스 대신 기능 유형 (예 :)을 사용하는 것이 바람직하다는 것을 이해 합니다.
Aleph Aleph

4
맞습니다. 가능하면 기능 유형을 사용해야합니다.
Yoav Sternberg

그러나 필자의 경우 인터페이스 (SurfaceTextureListener)에는 여러 가지 메소드가 있습니다.
타쉬 펨히와

정말 고마워. 이 답변에는 더 좋아하거나 특별한 마크가 있어야합니다. 왜냐하면 매우 유용한 정보이기 때문에 불행히도 일부 학습자는 Kotlin을 기사로 보거나 "Kotlin in Action"으로 SAM 주제를 볼 때 매우 혼란 스러울 수 있습니다.
TT_W

"Kotlin in Action"에서 그렇습니다. Java의 SAM 매개 변수에서 람다를 짧고 깔끔한 코드로 사용할 수 있지만 Kotlin의 SAM은 사용할 수 없습니다. 함수 유형은 Kotlin의 첫 번째 클래스이므로 SAM은 Kotlin의 의미가 아닙니다. 더 코 틀린 스타일입니다.
vg0x00

17

가장 좋은 솔루션은 Java 인터페이스 대신 유형을 사용하는 것입니다.

typealias MyInterface = (Location) -> Unit

fun addLocationHandler(myInterface:MyInterface) {

}

다음과 같이 등록하십시오 :

val myObject = { location -> ...}
addLocationHandler(myObject)

또는 심지어 클리너

addLocationHandler { location -> ...}

다음과 같이 호출하십시오.

myInterface.invoke(location)

현재 3 가지 옵션은 다음과 같습니다.

  • typealias (자바에서 호출하면 더러워 짐)
  • kotlin 인터페이스 (kotlin에서 호출 할 때 더러워지고 개체를 만들어야 함) 이것은 IMO의 큰 단계입니다.
  • 자바 인터페이스 (kotlin에서 호출 할 때 덜 지저분 해집니다. 람다는 앞에 인터페이스 이름이 필요하므로 객체가 필요하지 않으며 함수 괄호 규칙 외부에서 람다를 사용할 수 없습니다)

라이브러리를 Kotlin으로 변환 할 때 Kotlin의 Kotlin보다 Kotlin에서 Java를 호출하는 것이 더 깨끗했기 때문에 실제로 모든 인터페이스를 Java 코드로 남겨 두었습니다.


8

다음과 같이 인터페이스에 액세스하십시오.

 object : MyInterface {
    override fun onSomething() { ... }
}

6

다음 과 같은 Java 클래스 가있는 경우 :

recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerView, new RecyclerTouchListener.ClickListener()
        {
              //Your Code
        }));

이 코드를 Java에서 Kotlin으로 다음 과 같이 변환해야합니다 .

override fun showJozList (list : List<ResponseGetJuzList.Parameter4>) {
        adapter.addData(list)
        jozlist_recycler.addOnItemTouchListener(RecyclerTouchListener(
                activity ,
                jozlist_recycler ,
                object : RecyclerTouchListener.ClickListener
                    {
                          //Your Code
                    }))

Java 인터페이스 변환 :

new RecyclerTouchListener.ClickListener()

코 틀린 인터페이스 스타일 :

object : RecyclerTouchListener.ClickListener

1

인터페이스가 클래스의 리스너 메소드 용인 경우 인터페이스 정의를 함수 유형으로 변경하십시오. 코드가 더 간결 해집니다. 다음을 참조하십시오.

리스너 정의를 포함하는 클래스

// A class
private var mLocationMeasuredListener = (location: Location) -> Unit = {}

var setOnLocationMeasuredListener(listener: (location: Location) -> Unit) {
    mLocationMeasuredListener = listener
}

// somewhere in A class
mLocationMeasuredListener(location)

다른 수업

// B class
aClass.setOnLocationMeasuredListener { location ->
    // your code
}

-1
class YourClass : YourInterface {  
    override fun getTest() = "test"    
}

interface YourInterface {
    fun getTest(): String
}

val objectYourClass: YourInterface = YourClass()
print(objectYourClass.getTest())
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.