How to access class constructor parameters in a companion object - kotlin

I would like to access the arguments passed to the class constructor in a companion object :
class Home(private val activity: String) {
companion object {
fun doSomething() {
println(activity)
}
}
}
fun main() {
Home("Hello World").doSomething()
However, an error is raised when I run this code saying that activity is unresolved reference

A companion object is basically the equivalent of a Java static nested class (and that's how it's implemented under the hood), which means an instance of the static nested class could exist even with no instance of the outer class.
Example:
class Outer(private val activity: String) {
companion object {
fun doSomething() {
println("Hello, world!")
}
}
}
fun main() {
Outer.doSomething() // no new Outer instance here
}
If you want a non-static nested class (aka inner class) you can then reference properties of the outer class from within the inner class. That's because instances of the inner class are tied to instances of the outer class.
Example:
class Outer(private val activity: String) {
inner class Inner {
fun doSomething() {
println(activity)
}
}
}
fun main() {
Outer("Hello, world!").Inner().doSomething()
}
For more info, you can also have a look at Java documentation about nested (aka static) and inner (aka non-static) classes here: https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

Related

Returning reference to a singleton class instance within its functions

In the following code I would like to set a reference to the class instance so that static functions can return a reference to it:
open class TestRunner {
init {
instance = this
}
companion object {
private lateinit var instance: TestRunner
fun addTestSetups(vararg testSetups: () -> TestSetup): TestRunner {
for (setup in testSetups) {
testsSetups.add(setup)
}
return instance
}
}
}
But setting instance = this is not allowed. How can I return an instance of the class from a function while keeping the class as a singleton?
If I get you right, you want something like this:
abstract class TestRunner {
companion object : TestRunner()
}
This seems to work. Instead of keeping a variable that holds a reference to the class, simply referencing the name of the class is sufficient. However, to return an instance of the class from functions, the return type must be Companion:
open class TestRunner {
companion object {
fun addTestSetups(vararg testSetups: () -> TestSetup): Companion {
for (setup in testSetups) {
testsSetups.add(setup)
}
return TestRunner
}
}
}
This is not a true singleton because you can still create a new instance if you did this:
val testRunner = TestRunner()
However, if you never create an instance but only refer to the functions statically, it does behave like a singleton and the state of any private variables inside the companion object will still be maintained.
Update:
I came across this code on the Android developer site that shows an example of a class that is setup as a singleton:
class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
private val stockManager: StockManager = StockManager(symbol)
private val listener = { price: BigDecimal ->
value = price
}
override fun onActive() {
stockManager.requestPriceUpdates(listener)
}
override fun onInactive() {
stockManager.removeUpdates(listener)
}
companion object {
private lateinit var sInstance: StockLiveData
#MainThread
fun get(symbol: String): StockLiveData {
sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)
return sInstance
}
}
}
But it should be pointed out that this example requires functions that need to return an instance to first check if the instance variable is set and if not, create a new instance. I'm not sure what the point of that is since to call the function you already have an instance. So why bother create a new instance? Doesn't seem to make any sense.
object in Kotlin is the singleton, not the class its defined within. A companion object has the extra convenience of allowing you to call it by the name of that outer class. But it otherwise shares no hierarchy with it.
To make your class subclassable, you can't define the functions in the companion object. But you can make the class abstract so it can't be instantiated unless subclassed. Then make your companion object extend the abstract class so it will have all those functions available.
abstract class TestRunner{
open fun addTestSetups(vararg testSetups: () -> TestSetup): TestRunner{
//...
return this
}
companion object: TestRunner()
}
Usage:
TestRunner.addTestSetups(someTestSetup)
Note that your singleton is not an instance of TestRunner. It is a singleton instance of a subclass of TestRunner. But since you define no extra functions and override nothing, it behaves exactly like a TestRunner.
If you want a subclass:
abstract class ExtendedTestRunner: TestRunner() {
fun someOtherFunction() {}
companion object: ExtendedTestRunner()
}
The companions are not being subclassed, but their abstract parents can be.

Access delegate object from a method

Consider the following Kotlin code:
class Derived(n1: String, n2:String) : Teacher by TeacherImp(),Person by PersonImpl(n1, n2) {
// desire to call method of PersonImp object... possible??
}
Is there any way to access the delegate object instances?
Consider if the derived class wants to access a method of a delegate.
You can save the delegate(s) into private immutable property(s) - for example:
interface Teacher {
fun sayHelloTeacher() = println("Teacher hello")
}
interface Person {
fun sayHelloPerson() = println("Person hello")
}
class TeacherImp : Teacher {
fun sayHelloTeacherImp() = println("TeacherImp hello")
}
class PersonImp(val n1: String, val n2: String) : Person {
fun sayHelloPersonImp() = println("PersonImp hello $n1 $n2")
}
class Derived private constructor(private val t: TeacherImp, private val p: PersonImp) :
Teacher by t, Person by p {
constructor(n1: String, n2: String) : this(TeacherImp(), PersonImp(n1, n2))
init {
sayHelloPerson()
sayHelloTeacher()
t.sayHelloTeacherImp()
p.sayHelloPersonImp()
}
}
fun main(args: Array<String>) {
Derived("first", "second")
}
With this implementation the only public constructor is the same as the original, and which calls the private constructor that stores the actual objects.
Note: With reflection it may possible to access them without the extra constructor, but I think this is a straightforward solution to your problem.

Get companion class in companion object

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

Kotlin static methods and variables

I want to be able to save a class instance to a public static variable but I can't figure out how to do this in Kotlin.
class Foo {
public static Foo instance;
public Foo() {
instance = this;
}
}
Update: since this answer is getting a decent amount of upvotes, I really wanted to say that you shouldn't do the below, but instead just use object Foo { ... }, like Roman rightly points out in the comment.
Previous answer:
The closest thing to Java's static fields is a companion object. You can find the documentation reference for them here: https://kotlinlang.org/docs/reference/object-declarations.html#companion-objects
Your code in Kotlin would look something like this:
class Foo {
companion object {
lateinit var instance: Foo
}
init {
instance = this
}
}
If you want your fields/methods to be exposed as static to Java callers, you can apply the #JvmStatic annotation:
class Foo {
companion object {
#JvmStatic lateinit var instance: Foo
}
init {
instance = this
}
}
It looks that you want to define a singleton object. It is supported in Kotlin as a first-class concept:
object Foo {
...
}
All the boilerplate code with static field and constructor is taken care by the Kotlin automatically. You don't have to write any of that.
From the Kotlin code you can refer to the instance of this object simply as Foo. From the Java code you can referer to the instance of this object as Foo.INSTANCE, because the Kotlin compiler automatically creates the corresponding static field named INSTANCE.
first you create a simple class then after create a block followed by companion object keyword
for example:
class Test{
companion object{
fun getValue(): String{
return "Test String"
}
}
}
you can call this class function using class name dot function name
for example:
// here you will get the function value
Test.getValue()
You can create a companion object for the class, and if you want the field to be static you can use the annotation #JvmStatic. Companion object have access to private members of the class it is companion for.
See below an example:
class User {
private lateinit var name: String
override fun toString() = name
companion object {
#JvmStatic
val instance by lazy {
User().apply { name = "jtonic" }
}
}
}
class CompanionTest {
#Test
fun `test companion object`() {
User.instance.toString() shouldBe "jtonic"
}
}

Kotlin Factory on Inner Nested Class

I am trying to create a nested inner class in Kotlin with a companion object factory method (the equivalent of a static factory method in Java). Here's a simplified version of my code.
class OuterClass {
var myData:List<MyData> = List<>() //gets populated elsewhere
fun getItemFragment(position:Int) : Fragment() {
return InnerClass.Factory.newInstance(position)
}
inner class InnerClass : Fragment() {
companion object Factory {
fun newInstance(position:Int) : InnerClass {
var ic : InnerClass = InnerClass()
var bundle:Bundle = Bundle()
bundle.putInt("index", position)
ic.arguments = bundle
return ic
}
}
override fun onCreateView(inflater:LayoutInflater, container: ViewGroup, savedInstanceState:Bundle): View? {
//create and return view, omitted. Need access to myData
}
}
The compilier highlights "companion", saying "Modifier companion is not applicable inside inner class" and it also highlights the InnerClass() call, saying "Expression is inaccessible from a nested class Factory", use "inner" keyword to make the class inner.
How can I achieve what I'm trying to do here with the equivalent of a static factory method in Java?
You can have:
class OuterClass {
fun getItemFragment(position: Int): Fragment {
return InnerClass.Factory.newInstance(position)
}
class InnerClass : Fragment() {
companion object Factory {
fun newInstance(position: Int): InnerClass {
var ic: InnerClass = InnerClass()
return ic
}
}
}
}
However the following will not compile in Kotlin:
class Parent {
inner class Nested {
companion object Factory {
}
}
}
For the same reasons the following will not compile in Java:
public class Parent {
public class Nested {
public static boolean create(){
return false;
}
}
}
The culprit here is that nested inner classes in Kotlin, as well as nested non static classes in Java have an implicit reference to parent class instance. Since Kotlin aims to be highly interoperable with Java it follows the same rule.
Please see following questions for more in-depth explanation:
Why does Java prohibit static fields in inner classes?
Why can't we have static method in a (non-static) inner class?
up vote