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

来源:互联网 发布:吉林网络教育 编辑:程序博客网 时间:2024/06/08 15:23

本篇博客 按照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<Int>(3)

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

var ages = intArrayOf(19,20,21)

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

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

结果是:

192021

或者直接这样写:

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到10for (int i = 0;i<=10;i++){    System.out.println(i);}

Kotlin:

//打印0到10for (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到10for(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 <T> Array<out T>.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)    }}

输出的结果是:

012

可以看到,一个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)    }}

输出的结果是:

01245678910

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

fun test() {    val list: Array<String> = 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<Base>表示:

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<A>.f() // 调用 A.f()        super<B>.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] //解构声明

原创粉丝点击