Tho*_*ook 1 java reflection kotlin
在 Java 中,如果我有这样的类层次结构:
private interface Foo { }
private class FooBar implements Foo { }
private class FooZoo implements Foo { }
Run Code Online (Sandbox Code Playgroud)
然后我有一个这样的功能:
public int Return0IfFooBarElseIfFooZooReturn1ElseReturn2(Foo foo) {
if (foo instanceof FooBar) {
return 0;
} else if (foo instanceof FooZoo) {
return 1;
} else {
return 2;
}
}
Run Code Online (Sandbox Code Playgroud)
在运行时,将使用反射来确定foo. 在理想的世界中,我们希望避免让我们的代码使用反射。此外,据我所知,在 Java 中无法创建密封类型层次结构,这意味着您将始终需要提供一个 else 分支来编译代码。
但是在 Kotlin 中,您可以创建一个密封的类型层次结构,如下所示:
sealed class Foo {
object FooBar : Foo()
object FooZoo : Foo()
}
Run Code Online (Sandbox Code Playgroud)
然后你可以编写一个 when 表达式来打开类型并返回一个像这样的值:
fun return0IfFooBarElseReturn1(foo: Foo) = when (foo) {
is Foo.FooBar -> 0
is Foo.FooZoo -> 1
}
Run Code Online (Sandbox Code Playgroud)
对此有一个有趣的性质;也就是说,不需要 an else,因为when表达式会彻底检查密封类型层次结构。那么,从这个属性中,编译器能否获得足够的信息来编译字节码,该字节码在运行时不会使用反射来确定传递的实例是否属于给定类型?
或者换句话说,上面的 Kotlin 代码和下面的 Kotlin 代码在运行时有什么区别(关于反射):
interface Foo
class FooBar : Foo { }
class FooZoo : Foo { }
fun return0IfFooBarElseReturn1(foo: Foo) = when (foo) {
is FooBar -> 0
else -> 1
}
Run Code Online (Sandbox Code Playgroud)
我问这个,因为通常作为程序员,我们希望避免反射(在可能的情况下),但是密封类的官方 Kotlin 文档显示了一个使用is(https://kotlinlang.org/docs/reference /sealed-classes.html)。我在工作中所做的代码中也经常这样做,虽然我真的没有看到这样做有任何问题,但一些同事已经表达了担忧,因为它看起来像代码异味。
编译器在幕后做什么与这是否是好的做法无关。当您使用反射来微观管理对象的行为时,反射是代码异味,否则这些对象可能会通过多态来处理自己的行为。
在密封类的情况下,您正在使用一组有限的类,因此对它们的行为进行微观管理就不那么费劲了,但在我看来,如果您在定义它们的文件之外进行操作,仍然是一种味道。
这是一篇有趣的文章关于何时依赖反射而不是多态是有意义的。TLDR:
只有当多态行为确实是目标的行为时,多态才有意义。当它是观察者的行为时,您需要运行时输入。
所以如果你的 when语句要求每个对象做某事或计算某事,则很可能应该首选多态性。如果您的when语句对对象执行某些操作或需要以某种特定方式对其进行排序,则反射可能更合适。
我认为在一个领域,当密封类是解析文件或来自 Web 的东西的返回值时,使用密封类是有意义的。不像Expr所有内容都可以计算为 Double示例,当您从某个不可预测的文件中读取时,返回值可能具有不可预测的类型。您可能希望将返回值排序到特定的处理程序中。或者返回值可能是一个错误,您处理的错误与有效值不同。
您还可以使用密封类作为检查异常的更好替代方案。通过将结果包装在一个可以是有效结果持有者或错误的类中,您可以强制调用者在需要时处理错误,或者它可以将它们冒泡,而函数签名不必知道它的错误类型可能会遇到。然后在需要处理错误的任何级别,都可以用when语句解包。
| 归档时间: |
|
| 查看次数: |
292 次 |
| 最近记录: |