This question already has answers here:
Utils class in Kotlin
(3 answers)
Closed 1 year ago.
I was playing with Kotlin, and creating Util class with different ways. I am approaching a way that works best for calling by either Kotlin or Java.
Now I have created many types of Util. And now I am very confused which is best to use and most important why? I am finding best way considering Heap, Memory, Performance.
My question may look stupid for you guys, but I am in maze and can't come to a solution myself.
Here is my playground.
I have created 5 Kotlin files. in which I have put foo() method. and tried to call by Kotlin and Java.
Calling class Bar.kt
class Bar {
fun bazz() {
UtilClass.instance.foo()
UtilClassObject.UtilClassObject.foo()
UtilCompanionObject.foo()
UtilFileObject.foo()
foo() // from UtilFile
}
}
Calling class Qux.java
public class Qux {
public void bazz() {
UtilClass.Companion.getInstance().foo();
UtilClassObject.UtilClassObject.INSTANCE.foo();
UtilFileKt.foo();
UtilFileObject.INSTANCE.foo();
UtilCompanionObject.Companion.foo();
}
}
And here is the maze that makes me confused to choose best.
UtilClass.kt
class UtilClass {
fun foo() { ... }
companion object {
val instance = UtilClass()
}
}
UtilClassObject.kt
class UtilClassObject {
object UtilClassObject {
fun foo() { ... }
}
}
UtilCompanionObject.kt
class UtilCompanionObject {
companion object {
fun foo() { ... }
}
}
UtilFile.kt
fun foo(){ ... }
UtilFileObject.kt
object UtilFileObject {
fun foo() { ... }
}
It may take to answer my question and explaining it well. So I really appreciate your efforts in advance.
All options are present on the Kotlin reference page for interop between Kotlin and Java: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html
Your options to call from Java something on class MyUtil and call it without an instance such as MyUtil.foo() then you would simply do one of the two options:
// smallest byte code,
// static invocation of foo() from Kotlin side,
// also static call from Java to foo()
object MyUtil {
#JvmStatic fun foo() { ... }
}
or
// creates two classes,
// static lookup of companion followed by virtual call on that instance to foo() from Kotlin,
// Java is a static call to foo()
class MyUtil {
companion object {
#JvmStatic fun foo() { ... }
}
}
And you would call it the same from Kotlin MyUtil.foo(). This is specifically the model of making a Kotlin method static.
Both examples look the same from Java in that they are just direct static calls to a static method. From Kotlin the first example is a static call as well, the second looks up an instance of the companion first and then does a virtual call on the method. The Second example creates two classes, the other only creates a single class.
The other options you present are not more efficient and are uglier syntax. Based on smallest byte code, fewest classes, and fastest performance pick the first example that is 1 class only and all static calls.
Related
In the below, since T is reified, I want to use it "almost as if it were a normal class" by accessing its companion object.
class Cls {
companion object {
fun method() { }
}
}
inline fun <reified T> func() {
T.method() // error
}
fun main() {
func<Cls>()
}
But fails with
Type parameter 'T' cannot have or inherit a companion object, so it cannot be on the left hand side of dot
So it seems that a significant amount of information is lost. I get the same error with and without reified. I was hoping a reified type parameter would a fuller generic implementation than Java's. I have a ton of experience in C++ templates.
I've found some workarounds (that are all pretty disappointing using reflection), but really I'm asking why this can't work.
I'm not sure this is answering all the questions, but it's too big for a comment.
First and as stated in the comments, the way the code is written, T is not necessarily a Cls so to allow this you'd need some changes:
open class Cls {
companion object {
fun method() { }
}
}
inline fun <reified T : Cls> func() {
}
open the class and let Kotlin know T is a Cls
However, even though it's inlined, this still wouldn't let you call the companion method because T has no companion. Even without generics:
open class Cls {
companion object {
fun method() { }
}
}
class Foo : Cls
fun main() = Foo.method() // doesn't work
Doesn't work because companions are not inherited. Why? It was a conscious decision by the Kotlin designers. As you know Kotlin aims to correct a lot of issues Java had and this was one.
Static methods in Java are bound at compile-time while overriding is based on dynamic binding at runtime. This becomes quite confusing when you mix both and Kotlin tried to avoid this. Here's an example:
class Cls {
public static void method() {
System.out.println("Cls' method");
}
}
class Foo extends Cls {
public static void method() {
System.out.println("Foo's method");
}
}
public class Main {
public static void main(String[] args) {
Cls parent = new Foo();
parent.method();
}
}
If method would truly be overridden it would print out Foo's method, but indeed this prints Cls' method. The reason is that there's no overriding, but there's shadowing happening. On the other hand, if the methods wouldn't be static, then you'd get Foo's method since it is indeed overridden. This apparently caused confusion amongst developers and Kotlin completely disallowed it.
This question already has answers here:
Kotlin calling non final function in constructor works
(3 answers)
Closed 1 year ago.
I have a (more complex) version of these 4 classes the problem is when I try to initialize Test() android studio tells me cannot call data.log() on a null object reference. Why is this? how can i fix it?
abstract class Test() {
protected abstract val data: CustomClass
init {
data.log()
}
}
class myClass(): Test() {
override val data = Hello()
}
abstract class CustomClass() {
function log() {
Log.i("TEST", "HELLO");
}
}
class Hello(): CustomClass() {
}
I have a lot of classes that extend Test() and Hello() I do not want to have to call data.log() in multiple classes to avoid repeating code
Try to evaluate your code step by step:
invoke myClass() -> myClass constructor called from your code
invoke Test() -> parent constructor called from myClass constructor
invoke Test's init -> init section called from Test constructor
NPE -> data field is not initialized yet
As you can see, the init section is called BEFORE the data is initialized. Solution to your problem is pretty simple, move the data field right into the Test's constructor and remove the abstract modifier:
abstract class Test(protected val data: CustomClass) {
init {
data.log()
}
}
class myClass(): Test(Hello())
P.S.: I hope this is just an example and you don't start your class names with lowercase. :)
My question might be noob but please help me. I don't understand what is purpose of not allowing non-open classes with "is" keyword in kotlin.
Sample code 1
fun main(){
val randomclassobject = RandomClass()
println(randomclassobject is someRandomInterface)
}
open class RandomClass{
}
interface someRandomInterface{
fun mustImplementThis()
}
The above code works perfectly fine
Now
Sample code 2
fun main(){
val randomclassobject = RandomClass()
println(randomclassobject is someRandomInterface)
}
class RandomClass{
}
interface someRandomInterface{
fun mustImplementThis()
}
without open keyword it shows the error "Error:(3, 34) Kotlin: Incompatible types: someRandomInterface and RandomClass"
Why open keyword really matters?
When you write it like this
class RandomClass {
}
interface SomeRandomInterface {
fun mustImplementThis()
}
It is not possible for any object to be an instance of both RandomClass and SomeRandomInterface because RandomClass itself does not implement SomeRandomInterface and it cannot have any subclasses that implement it either because it is not open (Kotlin classes by default cannot be extended unless you add open).
Since the compiler knows that this check cannot return true, it marks it as an error. Most other languages would probably just warn you that the check is useless, but Kotlin makes it illegal entirely.
On the other hand, when you write
open class RandomClass {
}
interface SomeRandomInterface {
fun mustImplementThis()
}
even though the class itself does not implement the interface, it could have a subclass that implements it, for example
open class RandomClass {
}
interface SomeRandomInterface {
fun mustImplementThis()
}
class RandomSubClass : RandomClass(), SomeRandomInterface {
fun mustImplementThis() {}
}
which means that the check can return true, so the compiler allows it in that case.
Imagine I had an interface like:
interface MyInterface {
fun doSomething()
}
And I was interop-ing between Kotlin and Java. I now want a constant static instance of this interface but I want that to be part of the interface. I could do this:
interface MyInterface {
fun doSomething()
companion object {
val CONSTANT = object: MyInterface {
override fun doSomething() { ... }
}
}
}
but that means I need to write MyInterface.Companion.getCONSTANT(). #JvmField doesn't work here.
I've also tried:
interface MyInterface {
fun doSomething()
object CONSTANT: MyInterface {
override fun doSomething() { ... }
}
}
}
Which works in other Kotlin files (I can write MyInterface.CONSTANT) but I'd have to write MyInterface.CONSTANT.INSTANCE in Java. This solution seems the closest to what I want.
Any solutions? I want to be able to write MyInterface.CONSTANT in both Kotlin and Java and have them refer to a single static final object that implements the interface.
I believe I could also convert my Interface to an abstract class but that's the last resort.
The issue of not being able to use #JvmStatic in interfaces is tracked in this ticket: https://youtrack.jetbrains.com/oauth?state=%2Fissue%2FKT-6301
It is fixed by now and one comment says
Fix would be avaliable in 1.2.30 under '-language-version 1.3' option
How to use method references to refer to super class methods?
In Java 8 you can do SubClass.super::method.
What would be the syntax in Kotlin?
Looking forward to your response!
Conclusion
Thanks to Bernard Rocha!
The syntax is SubClass::method.
But be careful. In my case the subclass was a generic class. Don't forget to declare it as those:
MySubMap<K, V>::method.
EDIT
It still doesn't work in Kotlin.
Hers's an example in Java 8 of a method reference to a super class method:
public abstract class SuperClass {
void method() {
System.out.println("superclass method()");
}
}
public class SubClass extends SuperClass {
#Override
void method() {
Runnable superMethodL = () -> super.method();
Runnable superMethodMR = SubClass.super::method;
}
}
I'm still not able to do the same in Kotlin...
EDIT
This is an example how I tried to achieve it in Kotlin:
open class Bar {
open fun getString(): String = "Hello"
}
class Foo : Bar() {
fun testFunction(action: () -> String): String = action()
override fun getString(): String {
//this will throw an StackOverflow error, since it will continuously call 'Foo.getString()'
return testFunction(this::getString)
}
}
I want to have something like that:
...
override fun getString(): String {
//this should call 'Bar.getString' only once. No StackOverflow error should happen.
return testFunction(super::getString)
}
...
Conclusion
It's not possible to do so in Kotlin yet.
I submitted a feature report. It can be found here: KT-21103 Method Reference to Super Class Method
As the documentation says you use it like in java:
If we need to use a member of a class, or an extension function, it
needs to be qualified. e.g. String::toCharArray gives us an extension
function for type String: String.() -> CharArray.
EDIT
I think you can achieve what you want doing something like this:
open class SuperClass {
companion object {
fun getMyString(): String {
return "Hello"
}
}
}
class SubClass : SuperClass() {
fun getMyAwesomeString(): String {
val reference = SuperClass.Companion
return testFunction(reference::getMyString)
}
private fun testFunction(s: KFunction0<String>): String {
return s.invoke()
}
}
Don't know if it is possible to get the reference to super class's function, but here is an alternative to what you want to achieve:
override fun getString(): String = testFunction { super.getString() }
According to Bernardo's answer, you might have something like this. It doesn't have remarkable changes.
fun methodInActivity() {
runOnUiThread(this::config)
}
fun config(){
}
What is more, in the incoming 1.2 version you can use just
::config