Kotlin入坑的理由:
1,大大减少Java样板代码;
2,避免空指针异常等;
3,充分利用JVM,Android现有的库,和JAVA可以完全兼容;
4,Google推荐为Android开发的首选;
5,编译器的良好支持。
我们现在在新功能或者新项目中使用kotlin语言,而旧的项目只需要简单的维护的则继续使用java语言。不管怎样,你都可以尝试使用kotlin去编程。
Kotlin的使用
函数
函数定义使用关键字 fun,参数格式为:参数 : 类型
/**
* 计算两个数的差,返回类型为Int
*/
fun testSub(a: Int, b: Int): Int {
return a - b
}
kotlin语言默认支持lambda表达式
// 使用lambda表达式
fun testLambda() {
val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
println(sumLambda(1,2)) // 输出 3
}
变长参数测试
fun testVararg(vararg v:Int){
for(vt in v){
print(vt)
}
}
fun testVar(){
testVararg(1,2,3)
}
此外,kotlin还提供了便捷的字符串模板
/**
* 字符串模板
*/
fun testTemp() {
val s = "kotlin"
val curStr = "我正在使用$s"
print(curStr)
}
打印出来是”我正在使用kotlin“,可以省去java的字符串拼接;
通过上面的例子发现kotlin省略了;
号的结束符号,此外kotlin定义字段的时候,只有var
,val
两个修饰符,var
表示可变变量定义,val
表示不可变变量定义和Java中的final修饰的变量类似,并且kotlin可以声明变量的时候不指定变量类型,由编译器自动推断。
循环(for和while)
/**
* for循环
*/
fun testFor() {
for (i in 1..4) {
print(i)
}
for (i in 1..4 step 2) {
print(i)
}
//对集合进行迭代
val items = listOf("apple", "banana", "kiwi")
for(item in items){
println(item)
}
for(index in items.indices){
println("item at $index is ${items[index]}")
}
}
/**
* 使用两种while遍历
*/
fun testWhile() {
var x = 5
while (x > 0) {
println( x--)
}
var y = 5
do {
println(y--)
} while(y>0)
}
条件语句(if和when)
值得注意的是kotlin中并没有swith
语句,而使用了when
替代;
/**
* when 将它的参数和所有的分支条件顺序比较,直到某个分支满足条件。
* 类似于switch
*/
fun testWhen(x: Int) {
when (x) {
is Int -> print(x.toString())
else -> {
print("不是int类型")
}
}
}
一个 if 语句包含一个布尔表达式和一条或多条语句。
kotlin中使用以下的表达式来替换java中的三元操作符:
// 作为表达式
val max = if (a > b) a else b
使用 in 运算符来检测某个数字是否在指定区间内
/**
* 使用区间
*/
fun testIf() {
val x = 5
if (x in 1..8) {
println("x 在区间内")
}
}
Kotlin中的对象和类
Kotlin中的类都是继承Any
类(注意:并不是Object),它是所有类的超类,对于没有超类型声明的类是默认超类,Kotlin中与Java相同只能使用单继承。constructor
为构造函数,init
函数里面可以进行初始化操作。
class Person constructor(firstName: String) {
init {
println("FirstName is $firstName")
}
}
下面来看看对象和类的使用
/**
* 接口里面的成员变量默认为open类型
* kotlin接口与java 8类似,可以在接口里面实现方法
*/
interface TestInterface {
fun test() {
print("TestInterface接口中的test()调用")
}
}
/**
* 类属性修饰符
* abstract // 抽象类
* final // 类不可继承,默认属性
* enum // 枚举类
* open // 类可继承,类默认是final的
* annotation // 注解类
*
* 访问权限修饰符
* private // 仅在同一个文件中可见
* public // 所有调用的地方都可见
* internal // 同一个模块中可见
* 没有显式定义访问修饰符,默认为“public ”,对所有可见。
*/
open class Outer {
private val bar: Int = 1
private val name: String = "123456"
class Nested {
fun foo(): String {
val curString: String = "123"
return curString
}
}
inner class Inner {
fun innerTest(): String {
return [email protected]
}
}
open fun setInterface(test: TestInterface) {
test.test()
}
open fun test() {
}
}
/**
* Kotlin也只能单继承
*/
class OuterImpl : Outer(), TestInterface {
/**
* 如果继承和实现的方法中,有同样的test方式,需要这样调用父类或者接口的方法
* 另外:属性重写使用 override 关键字,属性必须具有兼容类型,每一个声明的属性都可以通过初始化程序或者getter方法被重写
* 你可以用一个var属性重写一个val属性,但是反过来不行。因为val属性本身定义了getter方法,重写为var属性会在衍生类中额外声明一个setter方法
*/
override fun test() {
super.test()
super.test()
}
override fun setInterface(test: TestInterface) {
super.setInterface(test)
}
}
/**
* 测试
*/
fun testOuter(): String {
var curStr = Outer.Nested().foo()// 调用格式:外部类.嵌套类.嵌套类方法/属性
val curName = Outer().Inner().innerTest()//调用内部类
//匿名内部类
Outer().setInterface(object : TestInterface {
override fun test() {
print("这里是一个匿名内部类")
}
})
OuterImpl().setInterface(object : TestInterface {
override fun test() {
print("这里使用了继承实现匿名内部类")
}
})
return "Outer.Nested().foo()中的curString=${Outer.Nested().foo()} Outer().Inner().innerTest()中name=$curName"
}
var curStr = Outer.Nested().foo()// 调用格式:外部类.嵌套类.嵌套类方法/属性
val curName = Outer().Inner().innerTest()//调用内部类
值得注意的是以上调用方式的不同。
Kotlin接口
Kotlin 接口与 Java 8 类似,使用 interface 关键字定义接口,允许方法有默认实现:
interface CustomInterface {
fun testOne() // 未实现
fun testTwo() { //已实现
// 可选的方法体
println("testTwo()")
}
}
接口中的属性只能是抽象的,不允许初始化值,接口不会保存属性值,实现接口时,必须重写属性
interface CustomInterface{
var name:String //name 属性, 抽象的
}
class CustomImpl:CustomInterface{
override var name: String = "Hubery" //重载属性
}
伴生对象
类内部的对象声明可以用 companion 关键字标记,这样它就与外部类关联在一起,我们就可以直接通过外部类访问到对象的内部元素。另外一个类里面只能够有一个伴生对象,也就是只能有一个companion修饰符。
java中我们常常使用static,而kotlin里面没有这个而使用伴生对象替代。不过并不完全相等。
companion object {
val EXTRA_ORDER_ID = "order_id"
}
类似于Java中如下定义 :
public static final String EXTRA_ORDER_ID = "extra_order_id";
需要注意的是:在kotlin语言中別的类需要访问就直接 类名.字段名
访问就行,而在java中调用kotlin的EXTRA_ORDER_ID,在这里就需要使用
类名.Companion.getEXTRA_ORDER_ID()
伴生对象的成员看起来像其他语言的静态成员,但在运行时他们仍然是真实对象的实例成员。比如还可以实现接口:
interface CustomInterface {
fun create(): T
}
class DemoClass {
companion object : CustomInterface {
override fun create(): DemoClass = DemoClass ()
}
}
数据类和密封类
数据类
kotlin使用data来修饰的只包含数据的类。
json字符串{"key":123,"title":"This is title"}
使用kotlin实现:
data class Bean(
@SerializedName("key") val key: Int,
@SerializedName("title") val title: String
)
使用java显示
public class Bean{
@SerializedName("key")
private int key;
@SerializedName("title")
private String title;
public int getKey() {
return key;
}
public void setKey(int key) {
this.key = key;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
看上面两段代码,发现kotlin的代码会简洁很多,特别是字段非常多的时候。
密封类
密封类用来表示受限的类继承结构:当一个值为有限几种的类型, 而不能有任何其他类型时。在某种意义上,他们是枚举类的扩展:枚举类型的值集合 也是受限的,但每个枚举常量只存在一个实例,而密封类 的一个子类可以有可包含状态的多个实例。
声明一个密封类,使用 sealed 修饰类,密封类可以有子类,但是所有的子类都必须要内嵌在密封类中。 此外,sealed 不能修饰 interface ,abstract class(会报 warning,但是不会出现编译错误)
sealed class SealedDemo
data class Const(val number: Double) : SealedDemo()
data class Sum(val s1: SealedDemo, val s2: SealedDemo) : SealedDemo()
object NotANumber : SealedDemo()
fun eval(SealedDemo: SealedDemo): Double = when (SealedDemo) {
is Const -> SealedDemo.number
is Sum -> eval(SealedDemo.s1) + eval(SealedDemo.s2)
NotANumber -> Double.NaN
}
密封类的关键好处在于使用 when 表达式 的时候,如果能够 验证语句覆盖了所有情况,就不需要为该语句再添加一个 else 子句了。
Kotlin入坑基础篇二