更新2020-12-23
open class BaseRequest {
val params = mutableMapOf<String, String>()
fun getParams(): List<String> {
return params.values.toList()
}
}
正如@slaw所说,这是kotlin编译器的行为,它是有效的,因为JVM使用地址而不是“签名”调用正确的方法。
我遇到了一种情况,似乎Kotlin允许子类创建与超类的getter相同的签名。
通常,函数具有相同的签名和不同的返回类型是不允许的。所以我对这种情况感到困惑。我不确定这是不是故意的。
open class BaseRequest {
val params = mutableMapOf<String, String>()
init {
params["key1"] = "value1"
}
}
class SpecificRequest : BaseRequest() {
init {
params["key2"] = "value2"
}
fun getParams(): List<String> {
return params.values.toList()
}
}
fun main() {
val specificRequest = SpecificRequest()
println("specificRequest.params: ${specificRequest.params}")
println("specificRequest.getParams(): ${specificRequest.getParams()}")
println("(specificRequest as BaseRequest).params: ${(specificRequest as BaseRequest).params}")
}
specificRequest.params: {key1=value1, key2=value2}
specificRequest.getParams(): [value1, value2]
(specificRequest as BaseRequest).params: {key1=value1, key2=value2}
如果我们看看反编译的Java代码,有两个方法具有相同的签名和不同的返回类型,这在Java中是不允许的。
java prettyprint-override">public class BaseRequest {
@NotNull
private final Map params;
@NotNull
public final Map getParams() {
return this.params;
}
/* ... */
}
public final class SpecificRequest extends BaseRequest {
@NotNull
public final List getParams() {
return CollectionsKt.toList((Iterable)this.getParams().values());
}
/* ... */
}
我知道函数名不合适,但有一个潜在的风险,即如果我们在.java中使用SpecificRequest,在将实例强制转换为它的超类之前,我们无法访问映射参数。而这可能会导致误解。
Java语言和JVM之间有区别。Java语言不允许在同一个类中声明两个名称相同但返回类型不同的方法。这是语言的限制。然而,JVM完全能够区分这两种方法。由于Kotlin是它自己的语言,它不一定要遵循与Java完全相同的规则--即使是在针对JVM时(因此编译为字节码)。
考虑以下Kotlin类:
class Foo {
val bar = mapOf<Any, Any>()
fun getBar() = listOf<Any>()
}
如果编译该类,然后使用javap
检查字节码,您将看到:
Compiled from "Foo.kt"
public final class Foo {
public final java.util.Map<java.lang.Object, java.lang.Object> getBar();
public final java.util.List<java.lang.Object> getBar();
public Foo();
}
fun test() {
val foo = Foo()
val bar1 = foo.bar
val bar2 = foo.getBar()
}
public static final void test();
descriptor: ()V
flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
Code:
stack=2, locals=3, args_size=0
0: new #8 // class Foo
3: dup
4: invokespecial #11 // Method Foo."<init>":()V
7: astore_0
8: aload_0
9: invokevirtual #15 // Method Foo.getBar:()Ljava/util/Map;
12: astore_1
13: aload_0
14: invokevirtual #18 // Method Foo.getBar:()Ljava/util/List;
17: astore_2
18: return
但有一个警告。以下内容将无法编译:
class Foo {
fun getBaz() = mapOf<Any, Any>()
fun getBaz() = listOf<Any>()
}
为什么?我不肯定,但我相信这与语法有关。Kotlin编译器总是可以根据您是使用foo.bar
还是foo.getbar()
轻松地判断要调用哪个函数。但是调用这两个getbaz()
函数的语法是相同的,这意味着编译器不能在所有情况下很容易地判断您要调用哪个函数(因此它不允许上述操作)。
我在一次面试中被问到以下问题: 问题:名称和签名相同但返回类型不同的方法。他问我,可能吗?这种类型叫什么。 有人能告诉我以下情况吗: > 上面的事情在任何情况下都是可能的(至少像一个在基类中,一个在派生类中?)如果是,是什么类型?比如编译或运行时多态? 在编译时多态性中,如果方法的返回类型与签名也不同,该怎么办?但只有函数的名称是相同的。还是编译时多态性吗? 在重写中,如果我有不同的返回类型,但方
我说的是Java,但这个概念也适用于其他语言-- 我们在同一个类上有两个方法,它们具有相同的基本功能,但提供不同的返回类型。这两种方法都会给你所有的东西,但一个得到一个可以提供对所有东西的访问的可迭代的,一个得到一个包含所有东西的集合。 我们知道你不能这样做(因为它不会编译): 那么,有人想过如何命名这些方法吗?这似乎是一个简单的解决方法: 然而,这显然有些冗长,可能不是最好的解决方案。我问的这个
我需要编写一个java方法来从一个对象中获取特定的信息。但是,该对象可以是A类型的,也可以是B类型的。下面是我的代码的一部分: 当我这样写它时,它会引发一个错误,说“重复方法”。我怎么才能让这个起作用?
问题内容: 我正在尝试使用RSA 7.5和Websphere 7服务器开发IBM JAX_WS Web服务。因为我是一个初学者,所以我遵循Java类优先方法,即首先创建Java类,然后生成WSDL文件。 当我尝试创建wsdl文件时,出现异常: java.security.PrivilegedActionException:com.sun.xml.internal.bind.v2.runtime.I
问题内容: 我目前正在使用Gson用Java编写RSS feed解析器。我正在将RSS的XML转换为JSON,然后使用Gson将JSON反序列化为Java POJO(有点回旋,但是有原因)。就下面列出的Feed#1( BBC )进行反序列化而言,一切工作正常,但是对于下面列出的Feed#2( NPR ),我开始抛出异常。 我认为我已经确定了问题,但不确定如何解决该问题: 这是由于以下两个RSS F
假设您有2个包,并且有名为-Test的公共类。 第一个包。测试 第二包测试 它们中的每一个都有实例变量-x。 在第一种情况下-int x=2; 在第二种情况下-int x=3; 我想导入FirstPackage。在第二个包内测试。测试并打印值为2的x。 我的代码: 但是输出是3。如何打印?