Как проверить, переопределил ли класс метод по умолчанию из интерфейса, использующего Reflection в Kotlin или Java? - PullRequest
4 голосов
/ 22 сентября 2019

У меня есть интерфейс с методом по умолчанию и два класса, которые реализуют этот интерфейс.Один из классов переопределяет метод по умолчанию, а другой - нет.

interface MyType {
  fun giveHello(): String = "Hello!"
}

class Polite: MyType {
  // Does not override giveHello()
}

class Rude: MyType {
  override fun giveHello(): String = "I don't like you"
}

Я получаю доступ к методу giveHello, используя отражение так:

val methodOfPolite = Polite::class.java.getDeclaredMethod("giveHello")
val methodOfRude = Rude::class.java.getDeclaredMethod("giveHello")

Есть одна странная вещьвещь здесьВежливый класс не переопределяет метод giveHello, но declaringClass этого объекта метода по-прежнему указывает на Polite.

Так есть ли способ проверить, действительно ли класс это сделалпереопределить метод интерфейса по умолчанию или нет?

Мой вариант использования выглядит примерно так (при условии, что мы можем получить запрашиваемое поведение в свойстве под названием isOverriden):

if (methodOfPolite.isOverriden) {
  // do something
} else {
  // do something else
}

Ответы [ 2 ]

6 голосов
/ 22 сентября 2019

Как описано в KT-4779 , в настоящее время функции Kotlin по умолчанию не реализуются с использованием реальных методов Java / JVM по умолчанию.Реализация по умолчанию живет вместо этого в статическом методе, и все классы, использующие эту реализацию по умолчанию, просто вызывают этот статический метод.Это сделано для того, чтобы функции Kotlin по умолчанию также работали с целью JVM 1.6, у которой их еще нет.

Итак, ваш код примерно компилируется в этот эквивалент Java:

public interface MyType {
  public String giveHello();

  public static class MyTypeImpls {
     public static String giveHello() { return "Hello!" }
  }
}

public final class Polite implements MyType {
  //does not override
  public String giveHello() { return MyType.MyTypeImpls.giveHello() }
}

public final class Rude implements MyType {
  //does override
  override fun giveHello() { return "I don't like you" }
}

Этопочему Java-отражение думает, что оба класса переопределяют функцию, т. е. потому что они на самом деле делают.

Вам необходимо использовать здесь отражение Kotlin, в частности declaredMemberFunctions и memberFunctions:

fun overridesGiveHello(cls: KClass<Derp>) =
        cls.memberFunctions.first { it.name == "giveHello" } in cls.declaredFunctions

println(overridesGiveHello(Polite::class)) //false
println(overridesGiveHello(Rude::class))  //true
2 голосов
/ 22 сентября 2019

В этом конкретном случае я думаю, что метод isDefault() должен вернуть true.

Я бы ожидал, что Polite::class.java.getMethod("giveHello") вернет метод, но не getDeclaredMethod(),но мы находимся в мире использования отражения Java для классов и интерфейсов Kotlin.Ожидания Java могут не оправдаться.

Вы можете использовать отражение kotlin, однако, используйте declaredMembers, чтобы получить свойства и функции из KClass.Обратите внимание, что требуется импорт из kotlin.reflect.full, поскольку используются методы расширения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...