interface MyInterface {
fun getName(): String
fun doSomething()
}
and I want to create abstract class with name field:
abstract class AbstractMyInterface(var name: String) : MyInterface {
override fun getName(): String = name
}
but compiler says me this:
Kotlin: Platform declaration clash: The following declarations have the same JVM signature (getName()Ljava/lang/String;):
fun (): String defined in AbstractMyInterface
fun getName(): String defined in AbstractMyInterface
How can I solve this problem and how can I extends this abstract class with super constructor contains name field?
I read that I can use private field, but I want to use this field in child classes.
I read that I can use @JvmField annotation in field but in this case I have a problem with extension.
Basically, whenever you have a var or val property inside of a class, it’s just syntatic sugar for a getName, a setName and a backing field name, and so in your case you literally just need to do this:
abstract class AbstractMyInterface(override var name: String) : MyInterface {
}
or if you want custom logic in your getter:
abstract class AbstractMyInterface: MyInterface {
override var name get() {//code goes here}
}
Also you should generally avoid functions with the name getSomething, setSomething in kotlin and use properties instead. getSomething is something that comes from java and is used there so often that kotlin decided to add a special syntax for that, properties. So your interface should look like this instead
In that case you can try to use the JvmName annotation to resolve your signature clashes. This allows you to rename functions in the bytecode. That said, it’s likely that you have to work around a few issues if you don’t use properties and instead write your own getters/setters.
Even though the method fun getName() and the getter of a property name are compiled to identical signatures on JVM, they are not the same as far as Kotlin itself is concerned. This means that you cannot access a property defined as val name by writing o.getName(), you cannot invoke a method defined as fun getName() by writing o.name, and you cannot override getName() with a property name or vice versa. It also means that in principle the property getter and the method can both exist, though on JVM the signature clash needs to be resolved.
That being said, I really do not understand why you want the getName method. Why not just define val name in the interface, implement it in the base class, and override the getter in the subclasses? Like this:
interface MyInterface {
val name: String
}
abstract class AbstractMyInterface(override val name: String): MyInterface
class MyInterfaceImpl(name: String): AbstractMyInterface(name) {
override val name: String get() {
// do something custom
return super.name
}
}
If you want to make the setter available to subclasses, you can do that as well (though you do have to explicitly override it in each subclass, see KT-12996):
abstract class AbstractMyInterface(name:String): MyInterface {
override var name = name
protected set
}
class MyInterfaceImpl(name: String): AbstractMyInterface(name) {
override var name: String
get() {
// do something custom
return super.name
}
protected set(name) {
super.name = name
}
}
Just to be crystal clear, you shouldn’t talk about a “variable” here, or you might misunderstand what you’re declaring when you do this:
interface MyInterface {
val name: String
}
The syntax used in this interface defines a property, which is just an abstract read access to a String value through the name: name.
The existence of a backing field for this property really depends on the implementations of the interface. You don’t have to have a “field” or “variable” holding the data to implement the name property, just like you don’t have to have a field in Java to implement a getter method such as getName().
You only have to provide a property accessor (getter). It can be defined by accessing a value stored in a backing field, or by computing a value each time it’s called.