kotlin 无法完全兼容java


#1

Kotlin 在设计时就考虑了 Java 互操作性。可以从 Kotlin 中自然地调用现存的 Java 代码 文档上这样说,
但是在实际使用上

package com.rxjava.http.exception;

public class ApiException extends Exception {

public int code;
public String message;
public String mmm;

public ApiException(Throwable throwable, int code) {
    super(throwable);
    this.code = code;
}

}

上面的ApiException 继承自 Exception ,Exception 继承Throwable ,Throwable 是有个 public String getMessage() {
return detailMessage;
}

在kotlin中调用
var exception = ApiException(Throwable(),1)
exception.code //正常
exception.message //编译报错
Overload resolution ambiguity. All these functions match. public final var message

java中调用
new ApiException(Throwable(),1).message 完全正常

java 代码已经打包成jar,显示 kotlin 中是无法完全调用已经 实现好的java 代码?是否有解决方法,特别是对用打包好的不能改的java代码,无法调用是致命的


#2

这是因为Kotlin的Throwable也有一个message属性…
召唤@bennyhuo


#3

java中的 getMessage() 方法到kotlin中 会自动生成 message,话是这么说,但是不开源的第三方sdk或者打好的 jar、aar 不能修改代码,在java 中能使用,到kotlin中完全不能用了这个时候要么放弃sdk,要么放弃kotlin,这就是kotlin 所说的 兼容java吗?感觉太坑了,完全名不副实。


#4

看看Throwable的源码吧message是val类型,ApiException里的message字段改一个名字不就行了? 你在子类重写一个父类val类型的字段当然报错


#5

你没细看标题和问题,换个字段肯定能解决,但是如果是不开源的sdk呢?或者aar,jar等方式调用的时候,不能改java源码呢?很多场景下是不允许修改已经封装好的代码的,kotlin所说的兼容,还要去改java代码,这难道就是所谓的兼容?


#6

我所寻求的是,在我们不改变已有的java代码的前提下,java中能调用,保证kotlin也可以使用的方法。


#7

只针对题中的问题就是 val造成的 ,至于java中则会提示你 final字段不能被继承与重写
所以我希望你能举出具体不兼容的例子 看看是否有解决办法


#8

不是列举了么,1楼就是具体的例子,在java ApiException 中定义message并不报错,其他java类中调用 Apiexception.message 也没有报错!但是kotlin中就是无法调用


#9

java中 不会 提示你 final字段不能被继承与重写!!!因为在java中 Throwable 并没有定义 final message


#10

还好啊,并没有觉得有啥问题。

Kotlin 对 Java 的兼容已经很出类拔萃了,说 100% 一点儿都不为过。


#11

100%? 那我上面说的场景 不该变java 代码的前提下,在kotlin 中怎么去调用?说说看,没问题? 第三方的sdk java 可以调用,kotlin 无法调用也没问题吗、


#12

class ExtApiException {
    public static String getMessage(ApiException a){
        return a.message;
    }
}

val a = ApiException()
val t = (a as Throwable).message
val r = ExtApiException.getMessage(a)

fun ApiException.realMessage() = ExtApiException.getMessage(this)
val i = a.realMessage()

能调了 嘿嘿


#13

谢谢,厉害:+1:,问了几个kotlin群和 好几个做kotlin 开发几年的人,都说没办法。


#14

在不改原代码的情况下,还是有 work arround 的,比如反射:

val field = ApiException::class.java.getDeclaredField(“message”)
field.get(ApiException())


#15

Kotlin 在属性合成上,会对一些 Java 方法本身造成一些影响,但从代码设计的角度,ApiException 这个类定义 message 的行为本身就很蠢,所以用这个来说 Kotlin 就无法兼容 Java 是有失偏颇的。

举个更常见的例子,Java 的泛型有 raw 类型,Kotlin 必然对这个是不兼容的。那么我们就说 Kotlin 不能自然的调用 Java 吗?

Kotlin 的语法比 Java 更严格,设计的时候想尽办法从语法上避免 Java 存在的问题,所以题主你是不是对完全兼容有什么误解?

至于你提的这个问题,根本原因在于 Kotlin 自己定义了一套 Throwable,换句话说你的 ApiException 在 Kotlin 看来,是继承自 kotlin.Throwable 的,它当中没有 getMessage 方法,对应的是 mesasge 这个成员,这个与绝大多数合成属性的情况还不一样,换句话说,你自己定义的类如果不继承存在映射关系的类型,几乎不会遇到类似的问题,因此不必过分担心。

Kotlin 在编译到 JVM 上时,会把 Throwable 映射成 java.lang.Throwable,所以你可以尝试把 ApiException 强转成 java.lang.Throwable,这样你就可以调用 getMessage 了。不过这时候你仍然无法调用到 ApiException 的 message 成员(尽管这个设计很蠢。。。),不过没有关系,因为 ApiException 的 message 与kotlin.Throwable 的 message 类型不同,区别在于一个是 var 另一个是 val,以及一个是平台类型 String! 另一个是 String?,通过这两个区别,我们都可以用一些手段让编译器自动帮我们选择合适的成员,具体做法如下:

fun <R, T> property1(property: KProperty1<R, T>) = property
fun <R, T> mutableProperty1(property: KMutableProperty1<R, T>) = property

val ApiException.throwableMessage: String?
        get() = property1(Throwable::message).get(this)

var ApiException.apiMessage
    get() = mutableProperty1<ApiException, String>(ApiException::message).get(this)
    set(value) {
        mutableProperty1<ApiException, String>(ApiException::message).set(this, value)
    }

当然,不通过是否 mutable 也可以使用是否 nullable 来做区分,例如我们定义一个 apiMessage2 来读取 ApiException 的 message,当然这里因为使用了 property1 这个方法,所以我们只能得到一个只读的变量:

val ApiException.apiMessage2: String
    get() = property1<ApiException, String>(ApiException::message).get(this)

以上看似使用了反射,但实际上并不需要引入反射包,也没什么性能问题。

这种情况,只能说 ApiException 不是 Kotlin 友好的类型,对于这样的类型,或者说类似的 Java 并不怎么好的代码,包括典型的 raw 类型的代码,建议用 Java 去访问,或者进行适当包装再交给 Kotlin 去调用。

当然,我最建议的是,如果有同事写了这样愚蠢的代码让你调用,离他远点儿,免得被带坏。


#16

听benny一席话,胜读十年书。:thinking:


#17

ApiException 单从java考虑,我并不觉得有什么问题,倒是java Throwable中的属性private String detailMessage; get方法却是 public String getMessage();至于一开始说的不兼容,是因为遇到这个问题,我问了几个说自己两年kotlin 开发的人员和几个kotlin开发群,都说不改变java 代码不能调用,现在 [dj_dj_dj] 、 [vincentlauvlwj] 、 [bennyhuo]的提供的3个方案确实是可行的,感谢大家的思路和方案。


#18

哈哈,感谢你提供了一个不错的话题,大年初一写了篇文章~~


京ICP备16022265号-2 Kotlin China 2017 - 2018
本站由腾讯云提供计算服务