我想更好地理解与内联值类相关的Java/Kotlin互操作.下面是我try 互操作的一些示例代码,下面是一些注释:

  1. can直接导入Java中的内联值类,即import kotlin.Result
  2. cannot在Java中使用它们的构造函数方法,即Result.success
  3. 一旦在Java中构建,您cannot就可以使用它们的方法,即myResult.isSuccess

我在下面创建了一些解决方法.它们起作用...但似乎也有自己的锋芒-- case 和怪事.我有几个问题:

  1. "装箱"似乎是保存类型信息所必需的.是一种强制执行?以外的装箱的方法(其缺点是会触发不必要的空判断).我try 了类似fun <T, R: Result<T>> success(value: T): R = Result.success(value as T) as R的代码--它已编译,但在运行时抛出了java.lang.NoSuchMethodError错误(!!)

  2. 有没有其他方法可以做到这一点?有没有什么模块/库可以帮助实现Kotlin/Java内联值互操作?

  3. 这里的Java&lt;-&gt;kotlin互操作在从Java调用时导致isFailure个方法失go 成功/失败状态(没有显式的?装箱),这似乎是一个错误,但我将不胜感激!

装箱定义为here,从中我可以看到您可以通过使用泛型和接口来装箱,但我不知道如何使用它们来强制装箱并执行逻辑和类型判断.

Kotlin :

@file:JvmName("Inline")

package play

// Note: doesn't compile without `?`: 
//   incompatible types: no instance(s) of type variable(s) T exist so that
//   Object conforms to Result<String>
@JvmName("success") fun <T> success(value: T): Result<T>?
  = Result.success(value)
@JvmName("failure") fun <T> failure(t: Throwable): Result<T>?
  = Result.failure(t)

// Note: java compiles without `?` BUT "failures" report isSuccess=true (!?!)
@JvmName("isSuccess") fun <T> isSuccess(r: Result<T>?): Boolean
  = r!!.isSuccess
@JvmName("isFailure") fun <T> isFailure(r: Result<T>?): Boolean
  = r!!.isFailure

Java测试代码:

package play;

import static org.junit.Assert.assertTrue;

import kotlin.Result;
import org.junit.Test;                                                    
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;                            
                                                                          
@RunWith(JUnit4.class)
public class InlineTest { 
  @Test                                                                   
  public void testResult() {
    Result<String> rString = Inline.success("hi");                        
    assertTrue(Inline.isSuccess(rString));
    assertSuccess(rString);

    Result<Integer> rInt = Inline.success(42);
    assertTrue(Inline.isSuccess(rInt));

    Result<Throwable> fail = Inline.failure(new Exception("test"));
    // Note: fails unless isFailure using `?` type
    assertTrue(Inline.isFailure(fail));
  }

  // just proves you can pass them to java functions
  <T>void assertSuccess(Result<T> r) {
    assertTrue(Inline.isSuccess(r));
  }
}

推荐答案

你不能在java中使用它们的构造方法,即Result.success

通常,value class can的伴随对象的方法可以像往常一样从Java访问.但是,Result.successResult.failure标记为@InlineOnly.

一旦在Java中构造,您就不能使用它们的方法,例如myResult.isSuccess

这是意料之中的.内联类的属性和方法被编译为接受包装类型的参数的静态方法,以避免装箱.它们也有一个损坏的名称,因此您无法从Java访问它们.

NoSuchMethodError是Java或Kotlin编译器的bug(我不确定).它应该要么not编译你的代码,要么在运行时编译它而不抛出NoSuchMethodError.这可能与KT-26131有关.

这里发生的情况是,您编写的success被编译为

Object success(Object value)

而不是

Result success(Object value)

Java代码查找与后者匹配的方法,但后者并不存在.

使用未装箱的Result<T>时,isFailure始终返回FALSE,因为isFailure通过判断结果是否是内部Failure类型的实例来确定结果是否失败.显然,您从Java传入的Result的实例不是Failure.如果您使用盒装Result<T>?,则会生成额外的拆箱操作.

用一些Java伪代码来说明其中的区别:

// for Result<T>
public static boolean isFailure(Object r) {
    return r instanceof Failure;
}

// for Result<T>?
public static boolean isFailure(Result r) {
    return r.unbox() instanceof Failure;
}

如果您可以控制内联类,那么在Java中使用它的另一种方法是让它实现一个接口like my answer demonstrates here.

否则,我只需要编写自己的非内联包装器,它包装内联类.

Java相关问答推荐

CriteriaQuery with max

Spring boot:Bean和动态扩展器

如何在Java中声明未使用的变量?

使用java访问具体子类特定方法的最佳方法是什么?

为什么我要创建一个单独的互斥体/锁对象?

具有多种令牌类型和段的复杂Java 17正则表达式

Spring Boot Maven包

如何使用Jackson将XML元素与值和属性一起封装

如何在Java记录中设置BigDecimal类型属性的精度?

SonarLint:只能有条件地调用方法(S)

如何在 spring 数据的MongoDB派生查询方法中使用$EXISTS

虚拟线程应该很快消亡吗?

如何配置空手道以使用FeignClient或RestTemplate代替ApacheHttpClient

从LineChart<;字符串、字符串和gt;中删除数据时出现特殊的ClassCastException;

在Java泛型中使用通配符时,如何推断类型

Java List有一个在一个位置添加多个元素的方法,但我找不到一个在一个位置删除多个元素的方法

使用同步方法中的新线程调用同步方法

获取月份';s在java中非UTC时区的开始时间和结束时间

如何在Java上为循环数组从synchronized迁移到ReentrantLock

ANTLR 接受特殊字符,例如 .标识符或表达式中的(点)和 ,(逗号)