Skip to content

Commit 0e24b91

Browse files
committed
hah
1 parent 14a223d commit 0e24b91

3 files changed

+178
-5
lines changed

_posts/2012-08-23-getting-started.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ Kotlin的稳定里程碑版本可以从JetBrains的[插件库](http://www.jetbra
5353
* 输入文件名,比如Foo
5454
* 这时候IDE会在编辑窗口的右上方提示你选择Kotlin运行环境(Kotlin Runtime)
5555
* 你需要指定到下载的Kotlin运行环境jar包(看下面)
56-
* 输入如下的代码:
56+
* 输入如下的代码: <!--abc-->
5757

5858
{% highlight java %}
5959
package hello

_posts/2012-09-09-classes-and-inheritance.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,9 @@ class C() : A(), B {
169169
super<B>.f() // 调用B.f()
170170
}
171171
}
172-
{% endhighlight %} <!----> <B></B>
172+
{% endhighlight %} <!---->
173+
174+
<B>haha</B>
173175

174176
类C同时继承A和B是可以的,而且我们在调用a()和b()函数时没有任何问题,因为他们在C的基类中只有一个实现。
175177
但是f()函数则在A,B中都有实现,所以我们*必须*在C中覆盖f(),并且提供我们的实现以消除歧义。

_posts/2012-09-13-java-interoperability.md

+174-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ original-doc: http://confluence.jetbrains.net/display/Kotlin/Java+interoperabili
77
Kotlin从最初设计时就一直考虑到和**Java**的互操作性。
88
已有的**Java**代码在Kotlin中可以非常自然地调用,而从**Java**中调用Kotlin代码,也相当顺畅。
99

10-
## 在Kotlin中调用Java代码
10+
# 在Kotlin中调用Java代码
1111

1212
这一节我们介绍在Kotlin中调用Java代码的一些细节。在大多数情况下,直接使用即可:
1313
{% highlight java %}
@@ -31,7 +31,8 @@ fun demo(source : List<Int>) {
3131
Kotlin的关键字中,有一些在Java中是合法的变量**标识符**,如**in**, **object**, **is**等。
3232
所以在你喜欢的**Java**库中,可能已经使用了这些标识符作为变量或方法名称。
3333
在这种情况下,你仍然可以使用那些方法,但需要对其标识符进行转义,以免和Kotlin的关键字冲突。
34-
转义的方法是使用倒引号`\``:
34+
转义的方法是使用倒引号`` ` ``
35+
3536
{% highlight java %}
3637
foo.`is`(bar)
3738
{% endhighlight %}
@@ -74,11 +75,181 @@ if (a is java.util.List<*>) // OK: 但是无法保证列表的内容的类型。
7475

7576
## 不可型变数组 (Invariant arrays)
7677
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+
78243

244+
### Null安全
79245

246+
当从**Java**中调用Kotlin函数时,没有人阻止我们给非空参数传入一个null值了。
247+
这就是为何Kotlin对所有的**public**函数,会生成运行时检查,以防止遇到null。
248+
这样如果遇到null,会立即抛出NullPointerException。
80249

250+
### 属性
81251

252+
属性的getter会转换成get方法,setters变成set方法。
82253

83254

84255

0 commit comments

Comments
 (0)