10
votes

Simple sample class with companion object

class MyClass {
  companion object {
     val test = 25
  }
}

The value test can be accessed from by MyClass.test, but how to access from an instance of MyClass? If I have val sample = MyClass(), how do I then access test from sample? sample::class.test is not correct....is there a way?

The question has been raised: 'Why not simply use MyClass.test'?

I prefer to keep the question to 'how' rather than 'why', but since it has been asked I will try the 'why'. The same could also apply to the methods. Why not have static functions in a class and simply call Class.function() and pass the object as one of the parameters?

Consider when working with an object passed as a more abstract base class, with several classes possible for the object you are working with.

You could make a switch and for each possbile class and access the value (or function) from the appropriate class that way, but the idea of polymorphism is that you should be able to access class attributes like a method (even though a function method code for for all members of the same class) or a value common to all members of the class from an instance of an object of that class.

My solution so far is to simply implement the equivalent of MyClass in with test as a static

public class MyClass {
    static Integer test = 25;
    public Integer testGetter(){ return test; }    
}

There are easy solutions to this in Java, C++, python etc.... (I will provide code samples for each is that helps) and i would think there will be a better solution in kotlin than resorting to using Java.

The kotlin companion object provides an alternative (and with advantages) to the static for situations where class attributes are accessed without an object instance (like factories), but there is another use of static for cases where although an object instance may be available, a static is appropriate since a single attribute can be shared by all members of the class and the attribute is not instance dependant.

4
Out of curiosity, why not just use MyClass.test?Oliver Charlesworth
The companion object is shared between all instances of MyClass, so you don't really need an instance to access it. As mentioned, you can use use MyClass.test from anywhereRobCo
Yes, you do not need an instance. But you still have use cases to work from an instance. Consider from example an object passed as a parameter which is subclassed from the parameter type... and you wish to access a value from the companion object of the parameterinnov8
@innov8 - That would only be useful if you could access the companion object in a polymorphic way. (Though I suppose that's equivalent to the question you're actually asking!)Oliver Charlesworth

4 Answers

6
votes

Using reflection, you can go via companionObject:

sample::class.companionObject?.memberProperties?.find { it.name == "test" }
6
votes

The problems is that while object properties are accessible from outside the class provided they are not public, but properties of the companion object are not. This means adding getters (and if relevant setters) for any companion object properties to be accessed externally to the class.

class MyClass{
  companion object{
     val test = 25
  }
  var staticTest get() = test  // getter for test
}

then all that is needed for access is::

sample.staticTest

Or you can provide access to the companion object...

class MyClass{
    companion object{
        val test = 25
    }
    var companion = Companion
}

Then allowing full access to anything in the companion

2
votes

It is one other way to used static variable into kotlin like this way..

object AppConstant {
const val baseUrl : String = ""
const val KEY_PRODUCT_ITEM="productItem"
}

when access into any where into project like this way..

AppConstant.KEY_PRODUCT_ITEM

other wise import AppConstant. then only used KEY_PRODUCT_ITEM

0
votes

For most people looking at this question, the best solution is to do what Oliver said:

just use MyClass.test

A Companion object is the same across every instance, so it's much easier to access as a property of the class itself rather than a specific instance.

If your class is:

class MyClass {
  companion object {
     val test = 25
  }
}

To access test:

var sample = MyClass()
var t = MyClass.test // will be 25, note that this doesn't depend on #sample

I am aware that this isn't the answer OP is looking for, but his request is very specific and arguably not desirable by anyone who arrives at this question.