Is there a way to declare virtual methods and virtual properties inside an abstract class in Kotlin like in c #?
C# Example:
public abstract class myAbstractClass {
private string _myString = "";
protected virtual string MyString
{
get { return _myString ; }
set { _myString = value; }
}
public virtual string getMyString(){
return _myString
}
}
I'm not familiar with C#, but if I understand the virtual and protected keywords correctly then it seems you want an overridable property that can be read from outside the class but can only be set from within the class or by a subclass. If that's the case then I believe the equivalent Kotlin code would be:
abstract class MyAbstractClass {
open var myString = ""
protected set
}
But if you really need the two properties and the function then the equivalent would be:
abstract class MyAbstractClass {
private var _myString = ""
protected open var myString by ::_myString
open fun getMyStringAlt() = _myString
}
Unfortunately, at least on the JVM, the getMyStringAlt() function cannot be named getMyString() because it clashes with the getter for the myString property. I'm not sure if there's a workaround.
The equivalent code would be:
abstract class MyAbstractClass {
protected open var myString = "foo"
open fun customGetString() = myString
}
This gives you a myString property that can be overriden by subclasses, and a customGetString function can can be overridden by subclasses. But if they don't override it, they get the default behaviour. Some examples:
class ConcreteClassA : MyAbstractClass()
class ConcreteClassB : MyAbstractClass() {
override var myString = "bar"
}
class ConcreteClassC : MyAbstractClass() {
override fun customGetString() = myString + "extra"
}
class ConcreteClassD : MyAbstractClass() {
override var myString = "baz"
override fun customGetString() = myString + "extra"
}
fun main() {
println(ConcreteClassA().customGetString())
println(ConcreteClassB().customGetString())
println(ConcreteClassC().customGetString())
println(ConcreteClassD().customGetString())
}
Output
foo
bar
fooextra
bazextra
Related
I am using class delegation in Kotlin and wondering if it is possible to make the delegated method private in Kotlin
interface A{
fun test(name: String)
}
class A1:A{
fun test(name: String): String = name
}
interface C{
fun myTest(name: String)
}
class C1(a:A){
fun myTest(name: String) = a.test(name)
}
class B(a:A): C by C1(a) {
// I can call "mytest" here
fun anotherMethod() = myTest("hi")
//But I want to make "myTest" private
}
val b = B(A1())
//This should not be possible
//b.myTest()
Interface is used to expose functions for public API, if B is A, then it must have a public member test.
You shouldn't implement A if you don't want test() to be available as public member:
class B(val a: A) {
fun anotherMethod() = a.test("hi")
}
Kotlin code like this:
class Foo {
companion object {
fun a() : Int = 1
}
fun b() = a() + 1
}
can trivially be changed to
object FooStatic {
fun a() : Int = 1
}
class Foo {
fun b() = FooStatic.a()
}
I'm aware that the companion object can be used to allow use as real java static function, but are there any other advantages to using the companion object?
One of the key differences is visibility of the members.
In a companion object, visibility to the containing class is as-if the members were part of the class - this is not the case for a raw object.
The example below shows that you cant use an "object" to implement private static internals of a class.
package com.example
class Boo {
companion object Boo_Core {
// Public "static" call that non-Boo classes should not be able to call
fun add_pub(a:Int) = a+1;
// Internal "static" call that non-Boo classes should not be able to call
private fun add_priv(a:Int) = a+1;
}
// OK: Functions in Boo can call the public members of the companion object
fun blah_pub(a:Int) = add_pub(a)
// OK: Functions in Boo can call the private members of the companion object
fun blah_priv(a:Int) = add_priv(a)
}
//Same idea as the companion object, but as an "object" instead.
object Foo_Core {
fun add_pub(a:Int) = a+1
private fun add_priv(a:Int) = a+1;
}
class Foo {
// OK Foo can get Foo_Cors add_pub
fun blah_pub(a:Int) = Foo_Core.add_pub(a);
// ERROR: can not get to add_priv
// fun blah_priv(a:Int) = Foo_Core.add_priv(a);
}
class AnInterloper {
// OK Other classes can use public entries in Foo.
fun blah_foo_pub(a:Int) = Foo_Core.add_pub(a);
// ERROR Other classes can use public entries in Foo.
// fun blah_foo_priv(a:Int) = Foo_Core.add_priv(a);
// OK: Other classes can use public Boo classes
fun blah_boo_pub(a:Int) = Boo.add_pub(a);
// ERROR: Other classes can not use private Boo classes
// fun blah_boo_priv(a:Int) = Boo.add_priv(a);
}
Is there a way to get the javaClass of the companion class inside a companion object without knowing it's name?
I suppose I could get it by doing something like this:
open class TestClass {
companion object {
init {
val clazz = Class.forName(this::class.java.canonicalName.removeSuffix(".Companion"))
}
}
}
However, this does not work for class InheritingClass : TestClass(). It would still give me TestClass, not InheritingClass.
I was hoping for something more straightforward like this::class.companionClass.
Getting the class of the companion object of a given class will look like this:
TestClass::class.companionObject
Here's an example:
class TestClass {
companion object {
fun sayHello() = "Hello world"
}
}
If you want to get the class that contains the companion, since the latter is always an inner class of the former,
class TestClass {
companion object {
fun whichIsMyParentClass() = this::class.java.declaringClass // It'll return TestClass
}
}
And to further simplify, you'll also want to create an extension property:
import kotlin.reflect.KClass
val <T : Any> KClass<T>.companionClass get() =
if (isCompanion)
this.java.declaringClass
else
null
So, whenever you want to get the parent class of the companion object,
class TestClass {
companion object {
fun whichIsMyParentClass() = this::class.companionClass // It'll return TestClass
}
}
The companion class itself has no reference to the actual class as you can see in this bytecode
public final class TestClass$Companion {
private TestClass$Companion() { // <init> //()V
<localVar:index=0 , name=this , desc=LTestClass$Companion;, sig=null, start=L1, end=L2>
L1 {
aload0 // reference to self
invokespecial java/lang/Object <init>(()V);
return
}
L2 {
}
}
public TestClass$Companion(kotlin.jvm.internal.DefaultConstructorMarker arg0) { // <init> //(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
<localVar:index=0 , name=this , desc=LTestClass$Companion;, sig=null, start=L1, end=L2>
<localVar:index=1 , name=$constructor_marker , desc=Lkotlin/jvm/internal/DefaultConstructorMarker;, sig=null, start=L1, end=L2>
L1 {
aload0 // reference to self
invokespecial TestClass$Companion <init>(()V);
return
}
L2 {
}
}
}
The reference is only the other way around (see decompiled kotlin class)
public final class TestClass {
public static final Companion companion = ...
}
So you can either do it as you just did by cutting off the .Companion part of the class name or you reference it by hard with TestClass::class.java (what is in my opinion no problem and the best solution)
If you need to print the class name, you can add simpleName, such as
this::class.java.declaringClass.simpleName
I am new in kotlin and not able to understand how the getter and setter behave in kotlin, so if I set the setter to private. Then what is the way of updating the value.
package foo
class Person() {
var name: String = "defaultValue"
private set
}
If you set your setter to be private, then this setter will be accessible only from within its class. In other words you can use normal assignment even when your setter is private but only from within the class.
class Person() {
var name: String = "defaultValue"
private set
fun foo(bar: String) {
name = bar // name can be set here
}
}
fun main(args: Array<String>) {
Person().name = "foo" // error. Name can be accessed but can not be modified here as its setter is private.
}
For more information check the Kotlin's Visibility documentation.
the kotlin code above will be transform to java code by kotlin compiler more like as below:
package foo;
public final class Person{
private String name = "defaultValue";
public final String getName(){
return name;
}
private final void setName(String name){
this.name=name;
}
}
which means you can only change the name field in the Person class. another situation is if you want to modify the name property with private setter out of the Person class. you can using java reflection instead, for example:
val person = Person();
val field = Person::name.javaField!!.apply { isAccessible = true }
field.set(person, "bob")
println(person.name)// "bob"
val setter = Person::class.java.getDeclaredMethod("setName", String::class.java)!!
.apply {
isAccessible = true
}
setter.invoke(person, "john")
println(person.name)// "john"
With the code below, I am getting the following error in IntelliJ IDEA 13.1.6 and Kotlin plugin 0.11.91.AndroidStudio.3:
Platform declaration clash: The following declarations have the same JVM signature (getName()Ljava/lang/String;):
• public open fun getName(): kotlin.String?
• internal final fun <get-name>(): kotlin.String?
Java class, JavaInterface.java:
public interface JavaInterface {
public String getName();
}
Kotlin class, KotlinClass.kt
public class KotlinClass(val name: String?) : JavaInterface
I've tried overriding the 'getter' method by
adding override fun getName(): String? = name, but that produces the same error.
I can see one workaround by doing this instead:
public class KotlinClass(val namePrivate: String?) : JavaInterface {
override fun getName(): String? = namePrivate
}
But in my real-world case I have a number of properties to implement and need setters too. Doing this for each property doesn't seem very Kotlin-ish. What am I missing?
Making that variable private solves the problem.
public class KotlinClass(private val name: String?) : JavaInterface
You could use #JvmField for instructs the compiler not generate getter/setter, and you can implement your setters and getters. With this your code work well in Java (as attribute getter/setter) and Kotlin as property
Example:
JAVA:
public interface Identifiable<ID extends Serializable>
{
ID getId();
}
KOTLIN:
class IdentifiableImpl(#JvmField var id: String) :Identifiable<String>
{
override fun getId(): String
{
TODO("not implemented")
}
}
The annotation feature of Kotlin named #JvmName will solve the duplication problem in Java and Kotlin when having the same signature.
fun function(p: String) {
// ...
}
// Signature: function(Ljava/lang/String)
With the use of JvmName will be:
#JvmName("functionOfKotlin")
fun function(p: String) {
// ...
}
// Signature: functionOfKotlin(Ljava/lang/String)
IMHO most readable combination is field + explicit interface implementation by the single-expression function (combination of #Renato Garcia's and #Steven Spungin's answers):
Java:
public inteface SomeInterface {
String getFoo();
}
Kotlin:
class Implementation(#JvmField val foo: String) : SomeInterface {
override fun getFoo() = foo
}
Another work-around is to declare the properties in an abstract Kotlin class, then write a small java class that extends KotlinClass and implements JavaInterface.
// JavaInterface.java
public interface JavaInterface {
int getFoo();
void setFoo(int value);
}
// KotlinClass.kt
abstract class KotlinClass(open var foo : Int = 0) {
}
// JavaAdapter.java
class JavaAdapter extends KotlinClass implements JavaInterface {
// all code in KotlinClass, but can't implement JavaInterface there
// because kotlin properties cannot override java methods.
}
We have found that to use the same names without clashing, the ctor args must be private AND you must still override the interfaces methods. You don't need any additional backing fields. Also, your expression body assignment will not recurse, so you can safely use that syntax.
Java Interface
interface IUser {
String getUserScope();
String getUserId();
}
Kotlin Class
class SampleUser(private val userScope: String, private val userId: String) : IUser {
override fun getUserId() = userId
override fun getUserScope() = userScope
}
If you have direct control over the interface then the best approach is to write the interface in Kotlin. You can then write your class
public class KotlinClass(override val name: String?) : KotlinInterface
and still reference it from any Java code using the same interface as before. This looks a lot neater than setting all the properties to private and overriding the get function. Obviously if you can't migrate the interface to Java because you don't own it then that seems to be the only solution.
public interface JavaInterface {
public String getName();
}
public class KotlinClass(val namePrivate: String?) : JavaInterface {
private var name = namePrivate
override fun getName(): String? {
return name
}
}
Rename the variable to something else, or make it private if u dont want it to be public.
convert function to property instead of initializing property from a function.
for ex:
fun getCountriesList(): List<Country> {
val countries = mutableListOf<Country>()
countries.add(Country("in", "+91", "India", R.drawable.indian_flag))
countries.add(Country("us", "+1", "United States",R.drawable.us_flag))
return countries
}
to
val countriesList: List<Country>
get() {
val countries = mutableListOf<Country>()
countries.add(Country("in", "+91", "India", R.drawable.indian_flag))
countries.add(Country("us", "+1", "United States", R.drawable.us_flag))
return countries
}