基础要素:函数和变量

1、HelloWorld

让我们从最经典的 helloworld 开始吧:打印一个 Helloworld 字符串出来。

  1. fun main(args: Array) {
  2. println("HelloWorld")
  3. }

从这样一个简单的代码里面可以看出 kotlin 哪些特性和语法呢?

  • 定义方法使用 fun 关键字
  • 参数的类型写在名称的后面
  • 使用 println 来代替了 System.out.println 进行打印输出
  • 省略了作为代码结束的标识的分号

2、函数

在上面,我们已经定义了一个没有返回值的方法,那如果我们的方法是有返回值的,那这个时候,返回类型要定义在函数的哪个地方呢?

fun sum(a: Int, b: Int): Int {
return a + b
}

调用: println((2,3))
结果: 2

函数的声明以关键字 fun 开始,函数名紧随其后。这个例子中,我们的函数名是 sum ,接下来的就是参数列表。参数列表后面跟的是返回类型,他们之间用一个冒号隔开。如果不需要返回值的话,可以直接不写。函数的基本结构如下:
Kotlin基础 - 图1

表达式函数体

如果一个函数的函数体是由单个表达式构成的,可以用这个表达式作为完成的函数体,并去掉花括号和 return 语句:

fun max(a: Int, b: Int): Int = if (a > b) a else b

如果函数体卸载花括号里面,我们就说这个函数有代码块。如果他直接返回了一个表达式,他就有表达式体 。在 kotlin 代码中常常会看表达式体的函数,以后会慢慢的认识到这些表达式体的。

3、变量

举个例子:

val name = "laotie"
val age = 20

kotlin 声明变量是以关键字开始,然后是变量名称,后面是变量的类型,当然也可以不加。
上面的两个例子其实省略了类型声明,如果有需要的话,也可以显示地指定变量的类型

val name : String = "laotie"
val age : Int = 20

如果不显示的指定变量的类型,编译器会自动分析出变量的类型,如果变量没有初始化器,这个是就需要显示地指定出类型。

val answer : Int
answer = 1

如果不能提供可以赋给这个变量的值的信息,编译器就无法推断出它的类型了。

可变变量和不可变量

  • val(value)——不可变引用。使用 val 声明的变量不能在初始化以后再次赋值,就跟java中的 final 关键字的作用是相同的。
  • var(variable)—— 可变引用。这种变量的值可以被改变。

kotlin 推荐使用关键字 val 去声明一个变量,仅在必要的情况下换成 var 。在定义 val 变量的代码块执行期间,val 变量只能进行唯一一次初始化。但是 val 变量指向的对象可能是可变的,比如说:

val list= arrayListOf("laotie")
list.add("guozi")

可空变量

如果定义的变量可以为空的时候,需要用? 进行修饰:

var a : String ? = null

4、字符串模板

举个例子:

fun main(args: Array) {
val name = if (args.isNotEmpty()) args[0] else "Kotlin"
println("Hello $name")
}

上面的例子介绍了 kotlin 的一个新特新,叫做字符串模板 。在代码中我们声明了一个变量,在后面的字符串面值中我们就可以直接使用它。使用这种新特性的时候只需要在变量的前面加上 $ 符号,这样写代码要比java中的简洁。如果需要在字符串中打印出 $ 符号,这个时候就需要用到转译,即”$” 。

当然这么好用的东西不可能仅仅局限于变量,可以引用更加复杂的表达式,只要将表达式的外层用大括号嵌套起来。

fun main(args: Array) {
println("Hello ${if (args.isNotEmpty()) args[0] else "Kotlin"}")
}

类和属性

1、类

首先来看看java中的类(Person),目前它只有一个属性:name

public class Person {
private String name;

public Person(String name) {
    this.name = name;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}
}

如果将上面的代码转成 kotlin ,再看看 Person 类中的代码:

class Person(var name: String?)

在转换的过程中,可以发现 public 修饰符消失了,因为在 kotlin 中, public 是默认的修饰符,所以你可以省略它。

2、属性

属性是一个类中的重要组成部分,特别是在 JavaBean 中。在 kotlin 中属性是头等的语言特性,完全替代了 java 中的字段和访问器。在类中声明属性和声明一个变量是一样样的,都是使用关键字 val 和 var , val 表示属性只读,var 表示属性可读可写。

Kotlin基础 - 图2

基本上,当你声明属性的时候,就会自动声明对应的访问器。但是如此简洁的 Person 类中,底层也是实现了和 java 一样的功能,我们来调用一下这个类。

/** java **/
Person laotie = new Person("laotie", 20);
System.out.println(laotie.getName());
System.out.println(laotie.getAge());

可以看出 在java中调用 kotlin 代码编写的类其实是跟java编写类的调用方法一模一样的。
再看看在 kotlin 中如何调用

/** kotlin **/
var person = Person("laotie", 20)
println(person.name)
println(person.age)

调用方式比java要简洁一点,类似于直接调用属性字段的方式。

对于已经在java中定义的类,一样可以使用kotlin的属性语法。对于定义了getter、setter方法的属性将会被当成var属性进行访问,如果只定义了getter方法的属性将会被当成val属性进行访问。

3、自定义属性访问器

什么叫做自定义访问器呢?比如说,我们需要获取到 Person 对象是否已经成年,当前我们可以先获取到对象的 age 属性进行判断,我们也可以采用自定义访问器的方式来进行获取用户是否已经成年的状态。

class Person(val name: String, var age: Int) {
    val isAdult: Boolean
        get() {
            return age >= 18
        }
}

调用:

var person = Person("laotie", 20)
println(person.isAdult)

结果: true

可空类型

1、空属性定义

fun main(args: Array) {
//在变量的类型后面加上一个?,表示name属性接受空值,也就是null属性。
var name : String ? = "laotie"
name = null // 可以将null赋值给name
var age: Int = 20
age = null //这句代码在编译器上会直接报错,因为不能讲一个空值赋值给一个非空的属性
}

2、函数返回值可空

fun findPerson(): Person? {
return null
}

在返回值类型的后面添加一个? ,表示当前的方法有可能返回的是一个空值。

类型智能转换

举个例子:

public class TestBean {
public String getName(){
return "fulei";
}
}
public class TestBeanSon extends TestBean {
public String getChildName(){
return "zilei";
}
}

首先看java的写法:

TestBean testBeanSon = new TestBeanSon();
if (testBeanSon instanceof TestBeanSon){
((TestBeanSon) testBeanSon).getChildName();
}

就算明明已经知道了 testBeanSon 是 TestBeanSon 类型的,但是在调用的时候还是需要强制类型转换。
看看kotlin的写法:

var testBeanSon: TestBean = TestBeanSon()
if (testBeanSon is TestBeanSon) {
testBeanSon.childName
}

kotlin 在得知对象的类型以后,不会再需要强制转换,可以直接调用对应的方法。
for循环

//for循环的测试代码
fun testFor(){
var arrayOf = arrayOf(1, 2, 3, 4, 5, 6)
for (i in arrayOf) {
    println(i)
}

for (i in arrayOf.withIndex()){
    println(i.value)
}

for (i in arrayOf.indices){
    println(arrayOf[i])
}
}

When表达式

在kotlin中是不存在 switch 表达式,但是kotlin提供更加好用的表达式 when。那就让我们来见识一下这个表达式的魅力吧?

fun testWhen(obj: Any) {
when (obj) {
is String -> println("是一个字符串")
is Int -> println("是一个数字")
is Collection<*> -> println("是一个集合类型")
else-> println("不知道是什么")
}
}
fun main(args: Array) {
testWhen(listOf(1,2))
testWhen(1)
testWhen("HelloWorld")
testWhen(true)
}

打印结果:

是一个集合类型
是一个数字
是一个字符串
不知道是什么

在switch 中只能使用枚举、常量字符串、数字作为分支条件,而 when 接受任何对象。when 还可以作为和 if 一样的表达式进行返回结果使用:

fun testWhen(obj: Any): String {
return when (obj) {
is String -> "String"
is Int -> "Int"
is Collection<*> -> "Collection"
else -> "..."
}
}
fun main(args: Array) {
println("${testWhen(listOf(1, 2))}")
println("${testWhen(1)}")
println("${testWhen("HelloWorld")}")
println("${testWhen(true)}")
}

打印结果:

Collection
Int
String

这些只是when 的部分实例,其他的可以自行学习。

迭代数字:区间和数列

在 kotlin 中采用了区间的概念,区间的本质就是两个值之间的间隔,这两个值通常都是数字:一个起始值、一个结束值。使用 . . 运算符来表示区间。

var array = 1..5
注意kotlin的区间是包含的,意味着第二个值也是区间的一部分。

迭代Map

//map集合遍历
var map = mapOf<String,String>(Pair("楷模","kaimo"),Pair("迟恒","chiheng"),Pair("良宇","liangyu"),Pair("金总","jinzong"))
fun printMap(){
    for (pair in map){
        System.out.println("${pair.key}---${pair.value}")

    }

    for ((key,value) in map){
        System.out.println("$key---$value")

    }
}

in关键字的使用

使用 in 运算符来检查一个值是否在取件中,或者它的逆运算 !in 。

fun isLetter(c:Char)  =   c in 'a'..'z'|| c in 'A'..'Z'
println(isLetter('c'))

打印结果:
true