ChatGPT解决这个技术问题 Extra ChatGPT

Accessing Kotlin extension functions from Java

Is it possible to access extension functions from Java code?

I defined the extension function in a Kotlin file.

package com.test.extensions

import com.test.model.MyModel

/**
 *
 */
public fun MyModel.bar(): Int {
    return this.name.length()
}

Where MyModel is a (generated) java class. Now, I wanted to access it in my normal java code:

MyModel model = new MyModel();
model.bar();

However, that doesn't work. The IDE won't recognize the bar() method and compilation fails.

What does work is using with a static function from kotlin:

public fun bar(): Int {
   return 2*2
}

by using import com.test.extensions.ExtensionsPackage so my IDE seems to be configured correctly.

I searched through the whole Java-interop file from the kotlin docs and also googled a lot, but I couldn't find it.

What am I doing wrong? Is this even possible?

Please elaborate on does not work? Does it compile, throws an exception, or what? Also have you import package com.test.extensions.MyModel?
@meskobalazs see my edited answer.
@meskobalazs also, I can't even import that. I can only import com.test.extensions.ExtensionsPackage

g
goodwinnk

All Kotlin functions declared in a file will be compiled by default to static methods in a class within the same package and with a name derived from the Kotlin source file (First letter capitalized and ".kt" extension replaced with the "Kt" suffix). Methods generated for extension functions will have an additional first parameter with the extension function receiver type.

Applying it to the original question, Java compiler will see Kotlin source file with the name example.kt

package com.test.extensions

public fun MyModel.bar(): Int { /* actual code */ }

as if the following Java class was declared

package com.test.extensions

class ExampleKt {
    public static int bar(MyModel receiver) { /* actual code */ }
}

As nothing happens with the extended class from the Java point of view, you can't just use dot-syntax to access such methods. But they are still callable as normal Java static methods:

import com.test.extensions.ExampleKt;

MyModel model = new MyModel();
ExampleKt.bar(model);

Static import can be used for ExampleKt class:

import static com.test.extensions.ExampleKt.*;

MyModel model = new MyModel();
bar(model);

I understood, it means I can't use extension from Kotlin to Java unless I write static functions?
JFYI, You can also change the name of the class with @file:JvmName("Utils").
what if i create an extension with parameters?
@AmirG parameters will follow the instance. In this case it would be bar(model, param1, param2);
This was really a quick help, Thanks a lot
r
reducing activity

Kotlin top-level extension function are compiled as Java static methods.

Given Kotlin file Extensions.kt in package foo.bar containing:

fun String.bar(): Int {
    ...
}

The equivalent Java code would be:

package foo.bar;

class ExtensionsKt {
    public static int bar(String receiver) { 
        ...
    }
}

Unless, that is, Extensions.kt contained the line

@file:JvmName("DemoUtils")

In which case the Java static class would be named DemoUtils

In Kotlin, extension methods can be declared in other ways. (For example, as a member function or as an extension of a companion object.)


I
Ilker Baltaci

I have a Kotlin file called NumberFormatting.kt that has the following function

fun Double.formattedFuelAmountString(): String? {
    val format = NumberFormat.getNumberInstance()
    format.minimumFractionDigits = 2
    format.maximumFractionDigits = 2
    val string = format.format(this)
    return string
}

In java I simple access it over the file NumberFormattingKt in the following way after the required import import ....extensions.NumberFormattingKt;

String literString = NumberFormattingKt.formattedFuelAmountString(item.getAmount());

A
Aziz

With newer KotlinEx, you can directly call extension in java

ExtensionFileName.foo(field1...)

Basically, what it does is, it makes the receiver as first arguement and other arguments remain being at the same place

So For eg.

You have extension(in file Extension.kt)

Context.showToast(message:String){ 
...
}

In Java, you call it as

ExtensionKt.showToast(context, message);

A
Adam Arold

You can always see the actual Java code which is getting generated from your Kotlin code by going to Tools > Kotlin > Show Kotlin Bytecode, then clicking Decompile. This can help you tremendously. In your case the Java code will look like this if you have MyModelExtensions.kt

public final class MyModelExtensionsKt {
   public static final int bar(@NotNull MyModel $receiver) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      return $receiver.getName().length();
   }
}

you can improve over this by using @JvmName on the file containing bar:

@file:JvmName("MyModels")
package io.sspinc.datahub.transformation

public fun MyModel.bar(): Int {
    return this.name.length
}

and it will result in this code:

public final class MyModels {
   public static final int bar(@NotNull MyModel $receiver) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      return $receiver.getName().length();
   }
}

Using MyModels is in line with what Effective Java suggests for utility classes. You can also rename your method like this:

public fun MyModel.extractBar(): Int {
    return this.name.length
}

then from the Java side it will look idiomatic:

MyModels.extractBar(model);

C
Cristian Díez

It works for me:

https://i.stack.imgur.com/t1YLs.png

https://i.stack.imgur.com/koUIi.png

My project is an old android project created with Java; now I created the first kotlin file and added String extensions fun String.isNotNullOrEmpty(): Boolean {... }

and I could call it from java file using: StringUtilsKt.isNotNullOrEmpty(thestring).

My kotlin file name is StringUtils


N
NickUnuchek

You need to duplicate your functions in the class files:

Create Kotlin file , for ex Utils.kt

Enter the code

  class Utils {
                companion object {
                    @JvmStatic
                    fun String.getLength(): Int {//duplicate of func for java
                        return this.length
                    }
                }
            }

        fun String.getLength(): Int {//kotlin extension function
            return this.length
        }

OR

class Utils {
    companion object {

        @JvmStatic
        fun getLength(s: String): Int {//init func for java
            return s.length
        }
    }
}

fun String.getLength(): Int {//kotlin extension function
    return Utils.Companion.getLength(this)//calling java extension function in Companion
}

In kotlin use:

val str = ""
val lenth = str.getLength()

In Java use this:

String str = "";
 Integer lenth = Utils.getLength(str);

f
forresthopkinsa

The other answers here cover the case of calling an extension function located at the top level of a Kotlin package file.

However, my case was that I needed to call an Extension function located inside a Class. Specifically, I was dealing with an Object.

The solution is incredibly simple.

All you have to do is annotate your extension function as @JvmStatic, and voila! Your Java code will be able to access it and use it.


Why the downvote? My answer is correct and original.
T
Tomas Bjerre

When you extend a class like this:

fun String.concatenatedLength(str: String): Int {
    return (this.length + str.length)
}

fun f() {
    var len = "one string".concatenatedLength("another string")
    println(len)
}

It will compile to this:

import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

public final class ExampleKt {
  public static final int concatenatedLength(@NotNull String $receiver, @NotNull String str) {
    Intrinsics.checkParameterIsNotNull((Object) $receiver, (String) "$receiver");
    Intrinsics.checkParameterIsNotNull((Object) str, (String) "str");
    return $receiver.length() + str.length();
  }

  public static final void f() {
    int len = ExampleKt.concatenatedLength("one string", "another string");
    System.out.println(len);
  }
}

There are more examples here.


j
johnw188

As far as I can tell this isn't possible. From my reading of the extensions docs, it appears that

public fun MyModel.bar(): Int {
    return this.name.length()
}

creates a new method with the signature

public static int MyModelBar(MyModel obj) {
    return obj.name.length();
}

Then, Kotlin maps that function to calls of the form myModel.bar(), where if bar() isn't found in the MyModel class it looks for static methods matching the signature and naming scheme it outputs. Note that this is just an assumption from their statements about extensions being statically imported and not overriding defined methods. I haven't gotten far enough in their source to know for sure.

So, assuming the above is true there's no way for Kotlin extensions to be called from plain old java code, as the compiler will just see an unknown method being called on an object and error out.


This answer is not correct, they can be accessed. See accepted answer.
And the compiler isn't looking for static methods (especially not Java static methods). It's looking for extension methods that have been declared or imported in the same file.