Type 1:
class TestExample {
object Bell {
fun add(){
}
}
Class B{
TestExample.Bell.add()
}
Type 2:
class TestExample {
companion object Bell {
fun add(){
}
}
Class B{
TestExample.add()
}
In this type 1 and type 2, which is static example and which is singleton example? Both behaves similar behavior right?
From official Kotlin docs:
Object declarations
If you need a singleton - a class that only has got one instance - you
can declare the class in the usual way, but use the object keyword
instead of class
Companion objects
If you need a function or a property to be tied to a class rather than
to instances of it (similar to #staticmethod in Python), you can
declare it inside a companion object
Related
Aim
Have a function Book, which takes one of three Letter classes as argument myClass and then calls 'genericMethod()' from the abstract class which Letter*() has inherited.
Issue
If I try Book(LetterA()).read() I get the following error:
Type mismatch. Required: Class<SampleClassArguments.Alphabet> Found: SampleClassArguments.LetterA
Does Kotlin have any way to achieve this result?
Code
#Test
fun readBookTest() {
Book(LetterA()).read() /*<--error here*/
}
class Book(val myClass: Class<Alphabet>) {
fun read() {
val letterClass = myClass.getConstructor().newInstance()
letterClass.genericMethod(myClass.name)
}
}
class LetterA(): Alphabet()
class LetterB(): Alphabet()
class LetterC(): Alphabet()
abstract class Alphabet {
fun genericMethod(className: String) {
println("The class is: $className")
}
}
You need to define the Class type as covariant with the out keyword so any of the child classes is an acceptable argument:
class Book(val myClass: Class<out Alphabet>)
And when you use it, you need to pass the actual Class, not an instance of the class. You can get the Class by calling ::class.java on the name of the class:
#Test
fun readBookTest() {
Book(LetterA::class.java).read()
}
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.
I saw simple class which was look like:
class SomeClass extends Object{
int a;
int b;
...
...
}
Why this class was extended an Object class? As in documentation was written "Because Object is the root of the Dart class hierarchy, every other Dart class is a subclass of Object." in https://api.dartlang.org/stable/2.4.0/dart-core/Object-class.html.
What will happened if we will not extends Object? Or maybe it will be useful in some specific problems?
All dart classes implicitly extend Object, even if not specified.
This can be verified using the following code:
class Foo {}
void main() {
var foo = Foo();
print(foo is Object); // true
}
Even null implements Object, which allows doing:
null.toString()
null.hashCode
null == something
interface MyInterface {
fun getTheString(): String
}
class MyClass(var theString: String) : MyInterface {
...
}
normally when I have a variable in the constructor for a class, it creates a getter and setter for that variable. In MyClass, the methods getTheString() and setTheString(String) exist when not implementing MyInterface.
When MyClass implements MyInterface, I get the error:
Accidental override: The following declarations have the same JVM signature (getTheString()Ljava/lang/String;):
public final fun (): String defined in MyClass
public abstract fun getTheString(): String defined in MyClass
I also have the error: Class 'MyClass' is not abstract and does not implement abstract member public abstract fun getTheString(): String defined in MyInterface.
So I have a few questions:
Why are 2 getter methods getting generated with the same JVM signature when implementing the interface versus one getter method getting generated without implementing the interface?
Why is it complaining I haven't implemented a getTheString() method when this method is automatically generated by kotlin?
How can I get the getter generated by the variable to become the implementation of the method in the interface?
If the interface is indeed in Kotlin, and you can change it, it should be
interface MyInterface {
val theString: String
}
in the first place. Java will still see getTheString(), but it's nicer to both implement and use in Kotlin.
Otherwise a good option is
class MyClass(#set:JvmName("setTheString") var _theString: String) : MyInterface {
override fun getTheString() = _theString
}
Unfortunately, it still has a duplicate getter, and you can't make only the getter private. Or
class MyClass(private var _theString: String) : MyInterface {
override fun getTheString() = _theString
fun setTheString(value: String) {
_theString = value
}
}
Note that if the interface is in Java, getTheString() will be visible to Kotlin as a property.
See issues https://youtrack.jetbrains.com/issue/KT-6653 and https://youtrack.jetbrains.com/issue/KT-19444 on the Kotlin bug tracker.
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"
}
}