Kotlin快速入门(1) -- 与Java的对比学习

本篇博客 按照Kotlin官方文档,总结出了Kotlin与Java相比,常用语法的不同之处,方便快速入门Kotlin,本人才疏学浅,如有错误还请指正。

基础语法

1.定义变量:

Kotlin中的基本数据类型和Java差不多,只是形式上每种数据的首字母都是大写的:
Int Long Short Byte Float Double

不可变(只读)的变量

Java

final int a = 1;  

kotlin

val a = 1  
val a : Int = 1    

在Kotlin中,变量如果被初始化了,他的值是可以被推导出来的,所以这里既可以不指定他为Int类型,让编译器自己去推导,也可以显式指定出来。
此外,Kotlin中每句话结尾可以不使用分号!

可变的变量

Java

int a = 1  

Kotlin

var a = 1
var a : Int = 1

在Kotlin中,val用于修饰不可变的(只读)变量,就类似于Java中的final关键字,var用于修饰可变的变量,就类似于Java 中的普通的变量。 与 Java不同的是变量的名字在前面,变量的类型在后面,中间要以:隔开。
此外,在Kotlin中一条语句的结尾可以不用写;,当然如果写上也不会报错。

2.定义函数:

Java

public void eat(String food){
    System.out.println("I like eat "+ food);
}  

这样一个简单的Java方法对应到Kotlin中的语法如下:

kotlin

public fun eat(food : String) : Unit{
    println("I like eat $food")
}

当然,在kotlin中如果没有显示制定访问修饰符,那么默认为public,这就意味着这里的public可以省略,这里的Unit就对应于Java中的void,但在Kotlin中,如果没有返回值,那么Unit也是可以省略的,即下面这种形式:

fun eat(food : String){
    println("I like eat $food")
}

$ dollar符号是模板表达式开始的标志,这里可以理解为“取出变量food的值”,值得注意的是,Java中的System.out.println()在Kotlin中变成了println(),这和C语言中的输出函数的名字一样了。
此外,函数的参数还可以有默认值:

public fun eat(food : String = "Apple") : Unit{
    println("I like eat $food")
}

3.字符串模板

字符串可以包含一个模板表达式,它的结果会被连接到字符串中,在Java中,会用+号来达到类似的效果。
Java

String  animal = "dog";
System.out.println("There is a "+ animal);
System.out.println("Dog has "+animal.length()+"words");

Kotlin

val animal = "dog"
println("There is a $animal")
println("Dog has ${animal.length} words")

如果$后面跟的不再是一个变量,就要加上{}来表示取这个式子的值

4.数组

Kotlin中的数组和Java中的区别有点大,在Kotlin中Array 类代表着数组,[] 可以用于访问数组的元素,实际上 [] 被进行了操作符的重载,调用的是 Array 类的 settergetter 方法
创建一个数组有三种方式:
(1)通过指定大小,使用arrayOfNulls直接创建一个空数组:

var ages = arrayOfNulls(3)

(2)使用xxxArrayOf创建并初始化数组:

var ages = intArrayOf(19,20,21)

(3)使用lambda创建并初始化数组:

var ages = IntArray(3, { i -> i + 19 })
for (j in ages) println("$j")

结果是:

19
20
21

或者直接这样写:

var ages = Array(3, { i -> i + 19 })

Kotlin会自动根据lambda表达式的里面建立的映射关系推断出数组的类型。

5.流程控制语句

if

在Kotlin中,if是带有返回值的表达式,因此在Kotlin中没有三目运算符(x + y > 0 ? true : flase),就用if就可以实现。

Kotlin中作为表达式的用法(这种情况必须带有else分支语句):

val num = if(a > b) a else b

特别的是,if分支可以作为块,最后一个表达式是该块的值:

val num = if (a > b){
    print("Hello! My value is a ")
    a
}else{
    print("Hello1 My value is b")
    b
}

when

在Kotlin中没有switch语句了,取而代之的是when。

基础用法

Java:

switch (a){
    case 1:
        System.out.println("I am 1");
        break;
    case 2:
        System.out.println("I am 2");
        break;
    case 3:
        System.out.println("I am 3");
        break;
    default:
        System.out.println("I am default");
        break;
}

Kotlin:

when(a){
    1-> print("I am 1")
    2-> print("I am 2")
    3-> print("I am 3")
    else -> print("I am default")
}

在Java中,case后面只能跟常量表达式,而在Kotlin中却可以用任意的表达式(包括含有in,is的表达式):

var b = "abcde"
when(a){
     b.length-> print("My length is b.length.")
     else -> print("I am default.")
}

for

普通for循环

Java:

// 打印0到10
for (int i = 0;i<=10;i++){
    System.out.println(i);
}

Kotlin:

//打印0到10
for (i in 0..10){
    println(i)
}

在Kotlin中,for循环的形式变成了使用in关键字加上范围。

“foreach”循环

Java:

String[] list = new String[11];
for (int i = 0;i<=10;i++){
    list[i] = i+"";
}
//打印0到10
for(String s : list){
    System.out.println(s);
}

Kotlin:

//初始化一个String类型的数组
val list : Array<String> = Array(11,{index -> index.toString()})
    for (e in list){
        println(e)
}

6.break、continue 、return

break 结束最近的闭合循环
continue 跳到最近的闭合循环的下一次循环
return 返回函数的值或终止函数函数运行
标签的格式为 标签名@

在 break 和 continue 中使用标签

Java:

//用"out"作为外层循环的标记
out: for (int i = 0; i < 100; i++) {
        for (int j = 0; j < 100; j++) {
            if (j==10) break out;
            System.out.println("i="+i+"j="+j+"    ");
        }
}

Kotlin:

out@ for (i in 1..100){
        for (j in 1..100){
            if (j==10) break@out
            print("i=$i,j=$j    ")
        }
}

continue配合标签的使用和break类似。
Kotlin 中的表达式可以添加标签,标签通过 @ 结尾来表示,通过标签就可以实现 break 或者 continue 的快速跳转。

return标签

Kotlin:
先来看看forEach的实现原理:

/**
 * Performs the given [action] on each element.
 */
public inline fun  Array.forEach(action: (T) -> Unit): Unit {
    for (element in this) action(element)
}

forEach的参数是一个名为action的函数,内部使用一个for循环来遍历调用forEach的数组,并执行action函数。所以,可以把forEach的参数理解为一个匿名函数。
下面来看一个return使用场景:


fun test() {
    val list: Array<String> = Array(11, { index -> "${index.toString()}" })
    list.forEach {
        if (it == "3") return
        println(it)
    }
}

输出的结果是:

0
1
2

可以看到,一个return直接返回出了test()函数。但是如果我并不想返回到直接包围return的test函数,我只想返回到当前这个lambda表达式(匿名函数)的时候,就要使用标签了,这种效果类似于在循环中使用了continue(但是Kotlin中的forEach中不能使用continue)。

fun test() {
    val list: Array<String> = Array(11, { index -> "${index.toString()}" })
    list.forEach inner@{
        if (it == "3")  return@inner
        println(it)
    }
}

输出的结果是:

0
1
2
4
5
6
7
8
9
10

当然,还可以使用隐式标签,这样更方便,该标签与接受该 lambda 的函数同名。

fun test() {
    val list: Array = Array(11, { index -> "${index.toString()}" })
    list.forEach {
        if (it == "3")  return@forEach
        println(it)
    }
}

1.类的声明和构造函数

Kotlin中的类也是用class声明,类的声明包含类名,类头(指定类型参数,主构造函数等等),以及类主体,用大括号包裹,类头和类体是可选的。

class A {

}

如果没有类体可以省略大括号:

class EmptyClazz

Kotlin中的构造函数和Java中的构造函数的作用是一样的,但形式有所区别:
Java:

class Hello{
    public Hello(){
        System.out.println("Hello world!");
    }

    public Hello(String content){
        System.out.println("Hello "+ content);
    }
}

在Java中构造函数可以有多个重载,而在Kotlin中,构造函数则分为“主构造函数”和“二级构造函数”,类可以有一个主构造函数以及多个二级构造函数
Kotlin:

 class Hello constructor(content : String?){
    init {
        println("Hello ${content}")
    }

    constructor() : this(null) {
        println("Hello world")
    }

}

主构造函数是放在类头中的,用 constructor关键字标示,但如果没有注解或者可见性说明,也可省略constructor,主构造函数是不能包含初始化代码的,它的初始化需要放在init{}代码块中执行。
当然如果在参数前面添加了varval,则参数可直接变为类中的字段:

class Hello constructor(val content : String) {
    fun sayHello(){
        println("Hello"+content)
    }
}

此外如果主构造函数的参数可以用在初始化块内,那么他也可以在属性声明时直接赋值给属性,如:

class Hello constructor(content : String) {
    val a = content
} 

二级构造函数需要以constructor

constructor(age : Int) {
    println("Hello, I am $age")
}

需要注意的是,如果类有主构造函数,每个二级构造函数都要使用this 关键字直接或间接通过另一个二级构造函数调用主构造函数。

class Hello constructor(name : String) {
    constructor(name: String,age : Int) : this(name) {
        println("Hello,I am $name , $age years old")
    }
}

2.类的修饰符

属性修饰符(classModifier)

属性修饰符用于标示类本身的特性,这是Java是类似的:

  abstract //抽象类标示  
  final  //标示类不可继承,默认属性
  open  //类可继承,类默认是final的
  enum  //标示类为枚举
  annotation  //注解类
访问修饰符(accessModifier)

访问修饰符用于确定类的访问范围,这也和Java是类似的:

  private //只在该类(以及它的成员)中可见
  protected //只在该类(以及它的成员) 或 子类 中可见
  internal //同一个模块(module)中可见
  public//默认,任何地方都可见

3.创建类的实例

Kotlin中没有new关键字!!!
Kotlin中没有new关键字!!!
Kotlin中没有new关键字!!!
重要的事情说三遍!!!
Kotlin中直接通过类名就可以实例化一个类:

val invoice = Invoice()
val customer = Customer("Joe Smith")

4.继承

Kotlin 中所有的类都有共同的父类 Any ,它是一个没有父类声明的类的默认父类:

class Example // 隐式继承于 Any

Any 不是 java.lang.Object,事实上它除了 equals(),hashCode()以及toString()外没有任何成员了。
在继承一个父类时候,Java使用的是extends关键字,而Kotlin则使用了冒号:,如果父类有构造方法,子类还必须创建构造方法,并使用super关键字,调用父类的构造方法:
Java:

class A extends Base{
    public A(String content) {
        super(content);
    }
}

而在kotlin中,如果父类有构造方法,则在继承的时候就传值给父类即可:
Kotlin:

open class Base (content : String)

class A(content: String) : Base(content)

需要注意的是,类的默认修饰符是final,所以必须用open修饰父类,它才可以被继承。

5.重写方法

在继承的时候,如果要重写父类的方法,必须在方法前加上override,并且,只有被open修饰的方法才可以被重写:

open class Base {
    open fun v() {}
    fun nv() {}
}

class Derived() : Base() {
    override fun v() {}
}

这里的nv()由于没有用open修饰,就无法被子类重写。

6.重写属性

重写属性和重写方法类似,都必须加上override

open class Foo {
  open val x: Int get { ... }
}

class Bar1 : Foo() {
  override val x: Int = ...
}

7. 实现接口

Kotlin中实现接口和继承类一样,都是使用的:

interface MyInterface{
    fun bar()
    fun app(){
        //如果接口中的函数有函数体,则实现的时候可以不用重写
    }
}
class May : MyInterface{
    override fun bar() {
    }

}

8.重写规则

在 Kotlin 中,实现继承通常遵循如下规则:如果一个类从它的直接父类继承了同一个成员的多个实现,那么它必须复写这个成员并且提供自己的实现(或许只是直接用了继承来的实现)。为表示使用父类中提供的方法我们用super表示:

open class A {
    open fun f () { print("A") }
    fun a() { print("a") }
}

interface B {
    fun f() { print("B") } // 接口的成员变量默认是 open 的
    fun b() { print("b") }
}

class C() : A() , B {
    // 编译器会要求复写f()
    override fun f() {
        super.f() // 调用 A.f()
        super.f() // 调用 B.f()
    }
}

常见的类

1.嵌套类

一个类可以嵌套在其他类中:

class Outer {
    private val bar: Int = 1
    class Nested {
        fun foo() = 2
    }
}

val demo = Outer.Nested().foo() //==2

2.内部类

Kotlin中的内部类必须用inner标示出来:

class Outer {
    private val bar: Int = 1
    inner class Inner {
        fun foo() = bar
    }
}

val demo = Outer().Inner().foo() //==1

3.匿名内部类

Kotlin中的匿名内部类的形式相对于Java也有所变化:
Java:

window.addMouseListener(new MouseAdapter() {
    @Override
    public void mouseClicked(MouseEvent e) {
        //...
    }
});

Kotlin:

window.addMouseListener(object: MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) {
        // ...
    }
)

其实,Kotlin的匿名内部类的实例是通过“对象表达式”创建的。

4.数据类

Kotlin中的数据类的概念就成对应于Java中的JavaBeen,但它又比JavaBeen要简单得多。
Java:

public class Person {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Kotlin:

data class Person(val name: String, val age :Int)

编译器会自动根据主构造函数中声明的所有属性添加如下方法:

equals()/hashCode 函数
toString 格式是 “Person(name=john, age=42)”
copy() 函数
[compontN()functions] //解构声明

你可能感兴趣的:(KotlinNote,Kotlin,Java)