@@ -7,7 +7,7 @@ original-doc: http://confluence.jetbrains.net/display/Kotlin/Java+interoperabili
7
7
Kotlin从最初设计时就一直考虑到和** Java** 的互操作性。
8
8
已有的** Java** 代码在Kotlin中可以非常自然地调用,而从** Java** 中调用Kotlin代码,也相当顺畅。
9
9
10
- ## 在Kotlin中调用Java代码
10
+ # 在Kotlin中调用Java代码
11
11
12
12
这一节我们介绍在Kotlin中调用Java代码的一些细节。在大多数情况下,直接使用即可:
13
13
{% highlight java %}
@@ -31,7 +31,8 @@ fun demo(source : List<Int>) {
31
31
Kotlin的关键字中,有一些在Java中是合法的变量** 标识符** ,如** in** , ** object** , ** is** 等。
32
32
所以在你喜欢的** Java** 库中,可能已经使用了这些标识符作为变量或方法名称。
33
33
在这种情况下,你仍然可以使用那些方法,但需要对其标识符进行转义,以免和Kotlin的关键字冲突。
34
- 转义的方法是使用倒引号`\` `:
34
+ 转义的方法是使用倒引号`` ` `` :
35
+
35
36
{% highlight java %}
36
37
foo.` is ` (bar)
37
38
{% endhighlight %}
@@ -74,11 +75,181 @@ if (a is java.util.List<*>) // OK: 但是无法保证列表的内容的类型。
74
75
75
76
## 不可型变数组 (Invariant arrays)
76
77
Kotlin中的数组是[ 不可型变] ( posts/generics#declaration-site-variance ) 的,这一点和[ ** Java** ] ( http://c2.com/cgi/wiki?JavaArraysBreakTypeSafety ) 不同。
77
- 所有类型为java.lang.Object的引用,都转变为Any?,因为可能使用任何种类的引用。
78
+ 这意味着,Kotlin不允许我们将` Array<String> ` 赋值给` Array<Any> ` ,以避免潜在的运行时错误。
79
+ 它也不允许我们在调用** Java** 方法时,将子类的数组值传入到父类的数组参数上。
80
+ 大多数情况下,这一点并不会带来阻碍,但是如果真的需要在传递数组参数的时候支持型变,可以显式地做类型转换。
81
+
82
+ 在Java平台下,使用泛型类Array来表示数组,会带来大量的盒装和盒取(boxing and unboxing)操作。
83
+ 因为数组大多数是使用在性能关键的场景中,我们采取了补救方式,并定义了类型IntArray, DoubleArray,
84
+ CharArray等等。这些类和Array类并没有关系,并且直接编译成Java的原生类型。
85
+
86
+ ### 对象方法
87
+
88
+ 当** Java** 的类型被导入到Kotlin中时,所有类型为java.lang.Object的引用都被转化成Any?。
89
+ java.lang.Object和Any的最大区别,是Any并没有定义* 任何* 方法。这是由于Kotlin的[ 继承规则] ( posts/classes-and-inheritance#overriding-rules ) 所致。
90
+ 那么我们如果需要toString()、equals()时怎么办呢?
91
+
92
+ #### toString()
93
+ toString()定义为一个[ 扩展函数] ( posts/extension-functions ) 。它会在对象中寻找toString()成员方法,并调用。如果不存在这个方法,则返回默认的String值:
94
+ ` this.javaClass.getName() + "@" + System.indentityHashCode(this) ` 。
95
+ 从程序员的角度来看,这几乎和** Java** 没什么区别: 所有已经存在的toString()实现都正常工作,
96
+ 而如果你需要给自己的类自定义toString()时,直接定义这个函数就可以:
97
+ {% highlight java %}
98
+ calss A() {
99
+ fun toString() : String = "A"
100
+ }
101
+ {% endhighlight %}
102
+
103
+ 你不需要声明它为** virtual** ,而且只有当你将其父类的toString()声明为** virtual** 时,才可以在前面加上** override** 。
104
+
105
+
106
+ #### equals()
107
+ 在Kotlin中,` == ` 代表[ 受保护的equals()调用] ( posts/basic-operations#equality ) 。
108
+ 操作符左侧的表达式必须有一个equals的方法,接受Any?类型的参数并返回Boolean值。
109
+ 所以,任何** Java** 对象已经符合条件了。另一方面,和toString()情形类似,我们也有一个扩展函数equals()。
110
+
111
+ #### hashCode()
112
+
113
+ hashCode() 对** Java** 对象可用。
114
+
115
+ 在即将来临的Kotlin标准库中,我们计划设计一个Hashable接口。若要往一个非同一性Hash映射(non-identity hash-map)中放置对象,则必须继承这个接口。
116
+
117
+ #### wait()/notify()
118
+ [ Effective Java] ( http://java.sun.com/docs/books/effective )
119
+ 第69条建议我们** 优先使用并行计算工具类(concurrency utilities),而不是wait和notify** 。
120
+ 所以,这些函数在Any中并没有,只有Java对象才有。
121
+
122
+ #### getClass()
123
+ 想要获取对象的类型信息,可以使用扩展函数[ javaClass] ( posts/runtime ) 。getClass()在** Java** 对象中可用。
124
+
125
+ #### finalize()
126
+ 和toString()一样,finalize()可以被覆盖
127
+
128
+ #### clone()
129
+ clone()可以和toString()一样覆盖,但是必须有Cloneable父型。
130
+ 不要忘记[ Effective Java] ( http://java.sun.com/docs/books/effective ) 第11条:** 谨慎使用clone** 。
131
+
132
+
133
+ ### 继承Java类
134
+ Kotlin类最多只能继承一个** Java** 类,(可以继承任意数量的** Java** 接口),这个基类必须放在继承列表的第一个位置。
135
+
136
+ ### 访问静态成员
137
+ ** Java** 类的静态成员组成这个类的"类对象"。这种"类对象"并不能当作值来随便传递,但是仍然可以显式地访问其成员,如下:
138
+ {% highlight java %}
139
+ if (Character.isLetter(a)) {
140
+ // ...
141
+ }
142
+ {% endhighlight %}
143
+
144
+
145
+ # 在Java代码中调用Kotlin代码
146
+
147
+ 我们计划在将来定向到更多的平台,但是现在,Kotlin只编译到** Java** 平台。
148
+ 这意味着编译器生成** Java** 字节码,所以我们用Kotlin写的程序也可以用** Java** 调用。
149
+ 尽管如此,Kotlin语言中有一些概念在** Java** 中没有。这一节,我们简要描述一下这些概念如何映射到** Java** 的概念。
150
+
151
+ ### 包级别的函数 (Package-level functions)
152
+
153
+ 所有在** 包** ` package org.foo.bar ` 中定义的函数和属性,会放到* Java* 的类中,类名是org.foo.bar.namespace。
154
+ {% highlight java %}
155
+ pakcage demo {
156
+ class Foo() {
157
+ }
158
+ fun bar() {
159
+ }
160
+ }
161
+ {% endhighlight %}
162
+ {% highlight java %}
163
+ // Java
164
+ new Foo();
165
+ demo.namespace.bar();
166
+ {% endhighlight %}
167
+
168
+
169
+ ### 需检异常(Checked exceptions)
170
+
171
+ 上面提到,Kotlin并没有需检异常机制。所以,正常情况下,Kotlin定义的函数在** Java** 中的签名,
172
+ 并不包含throw语句。所以如果我们在Kotlin中定义如下函数:
173
+ {% highlight java %}
174
+ package demo
175
+
176
+ fun foo() {
177
+ throw IOException()
178
+ }
179
+ {% endhighlight %}
180
+
181
+ 并且我们在** Java** 中调用这个函数,并试图捕获异常:
182
+ {% highlight java %}
183
+ // Java
184
+ try {
185
+ demo.namespace.foo();
186
+ }
187
+ catch (IOException e) { // Error: foo()并没有在throws列表中声明会抛出IOException
188
+ // ..
189
+ }
190
+ {% endhighlight %}
191
+
192
+ 则我们会遇到** Java** 编译错误,因为foo()函数并没有声明IOException。
193
+ 这时候应该怎么办呢? 有几种方法:
194
+
195
+ * 第一种办法(下面的注释)是建立一个假的抛出异常的函数:
196
+ {% highlight java %}
197
+ // Java
198
+ <E extends Throwable > void mayThrow(Class<E > eClass) throws E {
199
+ // 什么都不做
200
+ }
201
+ {% endhighlight %}
202
+
203
+ 并这么使用:
204
+ {% highlight java %}
205
+ // Java
206
+ try {
207
+ mayThrow(IOException.class);
208
+ demo.namespace.foo();
209
+ }
210
+ catch (IOException e) { // 没问题了
211
+ // ...
212
+ }
213
+ {% endhighlight %}
214
+
215
+ * 第二种办法是捕获Throwable并且做一个* instanceof* 检查。这样并不优雅,但是可以成功。
216
+ * 第三种办法是在** Java** 中写一个包裹函数:
217
+ {% highlight java %}
218
+ void foo() throws IOException { // 在声明会抛出一个异常时,Java并不要求我们真的需要抛出一个异常。
219
+ demo.namespace.foo()
220
+ }
221
+ {% endhighlight %}
222
+ 现在可以直接调用foo()方法并捕获异常了。
223
+ * 第四种办法是在Kotlin中使用** throws** 标注给函数签名加上抛出列表:
224
+ {% highlight java %}
225
+ throws<IOException > fun foo() {
226
+ throw IOException();
227
+ }
228
+ {% endhighlight %}
229
+
230
+ ### 运行时类型信息
231
+ <div class =" warn " >
232
+ <strong >运行时泛型现在还没有实现</strong >
233
+ </div >
234
+
235
+ Kotlin的泛型会保留到运行时,这意味在新建对象的时候,我们会将类型信息作为参数传入到构造函数中:
236
+ {% highlight java %}
237
+ // Java
238
+ new SomeClassDesclaredInKotlin<Integer >(TypeInfos.Int()) // 显式地传入一个TypeInfo对象
239
+ {% endhighlight %}
240
+
241
+ 对于泛型函数来说,情况一致。
242
+
78
243
244
+ ### Null安全
79
245
246
+ 当从** Java** 中调用Kotlin函数时,没有人阻止我们给非空参数传入一个null值了。
247
+ 这就是为何Kotlin对所有的** public** 函数,会生成运行时检查,以防止遇到null。
248
+ 这样如果遇到null,会立即抛出NullPointerException。
80
249
250
+ ### 属性
81
251
252
+ 属性的getter会转换成get方法,setters变成set方法。
82
253
83
254
84
255
0 commit comments