kotlin语法分析(一)

来源:互联网 发布:haskell linux 编辑:程序博客网 时间:2024/06/03 12:32

AS环境的配置

项目下的 build 文件

buildscript {    ext.anko_version = '0.10.0-beta-2'//定义当前版本,方便后来引用    ext.kotlin_version = '1.1.2'//定义当前版本,方便后来引用    ext.support_version='25.0.3'    repositories {        jcenter()    }    dependencies {        classpath 'com.android.tools.build:gradle:2.2.2'        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"        classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"        // NOTE: Do not place your application dependencies here; they belong        // in the individual module build.gradle files    }}allprojects {    repositories {        jcenter()        maven { url "http://dl.bintray.com/kotlin/kotlin-dev" }    }}task clean(type: Delete) {    delete rootProject.buildDir}

model下的 build 文件

apply plugin: 'com.android.application'apply plugin: 'kotlin-android'apply plugin: 'kotlin-android-extensions'android {    compileSdkVersion 25    buildToolsVersion "25.0.3"    defaultConfig {        applicationId "com.ydl.testmykotlin"        minSdkVersion 19        targetSdkVersion 25        versionCode 1        versionName "1.0"        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"    }    buildTypes {        release {            minifyEnabled false            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'        }    }    kotlin {        experimental {            coroutines "enable"        }    }    dependencies {        compile fileTree(dir: 'libs', include: ['*.jar'])        androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {            exclude group: 'com.android.support', module: 'support-annotations'        })        compile 'com.android.support:appcompat-v7:25.3.1'        testCompile 'junit:junit:4.12'        compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"        compile "org.jetbrains.anko:anko-sdk25:$anko_version"        compile "org.jetbrains.anko:anko-sdk25-coroutines:$anko_version"        compile "org.jetbrains.anko:anko-appcompat-v7:$anko_version"        compile "org.jetbrains.anko:anko-common:$anko_version"        compile "com.android.support:recyclerview-v7:25.3.1"    }}

(1) kotlin的打印语句

println(“Hello , world”)
print(“Hello, World!”)

(2) java 的 打印语句

System.out.print(“Hello, World!”);
System.out.println(“Hello, World!”);

(3) variables

    像integer,float或者boolean等类型仍然存在,但是它们全部都会作为对象存在的。基本类型的名字和它们工作方式都是与Java非常相似的,但是有一些不同之处你可能需要考虑到:
    数字类型中不会自动转型。举个例子,你不能给 Double 变量分配一
个 Int 。必须要做一个明确的类型转换,可以使用众多的函数之一:

val i:Int=7  val d: Double = i.toDouble()  

    字符(char),不能作为一个数字来处理,在需要时我们必须要把他们转换为一个数字

val c:Char='c'  val i: Int = c.toInt()

    位运算也有一点不同。在Android中,我们经常在 flags 中使用“或”,所以我使用”and”和”or来举例:

// Kotlin  val bitwiseOr = FLAG1 or FLAG2  val bitwiseAnd = FLAG1 and FLAG2  // Java  int bitwiseOr = FLAG1 | FLAG2;  int bitwiseAnd = FLAG1 & FLAG2;  

字面上可以写明具体的类型,也可以不写,我们可以通过编译器自动的推断出来.

val i = 12 // An Int  val iHex = 0x0f // 一个十六  val l = 3L // A Long  val d = 3.5 // A Double  val f = 3.5F // A Float  

一个String可以像数组一样的被迭代使用

val s = "Example"val c = s[2] // 这是一个字符'a'// 迭代Stringval s = "Example"for(c in s){print(c)}

(4) Null

var name : String? = null // 可以为null
var name : String =null // error
还记得java中的 非空判断吧~
if(string != null){
  int length = string.length();
}
现在可以这么写了
val length = string?.length
val length = string!!.length // NullPointerException if string == null

(5)变量

  变量可简单的分为 var(可变变量)和val(不可变量),这个和java中的final 很相似,一个不可以变得变量初始化以后就意味着不能在改变它的状态,如果你需要这个对象修改之后的版本,那就会重新的创建一个对象,这让编程编程变得更加具有健壮性和预估型,在java 中,大部分的对象是可变的,那就意味这任何访问它的代码都可以更改它的状态,从而会影响程序的其他的地方.
  不可变的对象可以称作为线程安全的,因为它们无法去改变,也不用改变控制,因为所有的线程访问的都是同一个对象, 所以在kotlin中,如果我们使用不可变性,我们的编码方式也要有一些改变,一个重要的概念就是尽可能的使用 val ,除了个别情(特别是在Android
中,有很多类我们是不会去直接调用构造函数的),大多数都是可以的.
在kotlin中,我们尽可能的不要在变量中去声明类的类型,它会自动的从后面的语句中推断出来,这样可让代码清晰快速的修改,

val s = "Example" // A Stringval i = 23 // An Intval actionBar = supportActionBar // An ActionBar in an Activity

如果我们需要使用更多的范型类型,则需要指定:

val a: Any = 23val c: Context = activity

类,继承和函数

    kotlin遵守一个简单的结构和java还是有一点细微的差别,可以使用try.kotlinlang.org包下的
    怎么去定义一个类呢?
    如果你想定义一个类只需要使用class关键字就可以

class Actkotlin1 {    //函数的使用    fun add(a:Int,b : Int): Int{        return a+b;    }}

    这是默认唯一的构造器,大多数情况只需要使用这个默认的构造器,就是在他后面加上它的参数,如果这个类中没有任何内容 大括号可以省略的`

class Actkotlin1 (var name:String ,var phone: String)

那么构造函数的函数体呢? 可以写在init快中:

class Actkotlin1 (var name:String ,var phone: String){    init {    }}

    kotlin中 默认的所有的类都是继承自 Any 的 (和 java 的Object很相似),所有的类默认都是 不可继承的(final),我们只能继承 open 或者 是abstract

open class Animal (name: String)class Person (name : String ,phone : String) : Animal(name)

    当我们只有单个构造器时,我们需要从父类继承下来的构造器中制定需要的参数,替换 java中的 super

继承

kotlin中所有的 类都有以恶搞通用的超类Any,这是一个没有父类型的类的超类

class Example 

Any 不是 java 中的object类,特别说明除了 equals(), hashcode(), toString()外,他不具有任何的成员函数
要声明一个显式的超类型,将冒号后面的类型放在类头中

open class Base(name : String)class Childen (name : String) : Base(name)

如果类具有主构造函数,则可以使用主构造函数的参数初始化 基类型 .
如果类没有主构造函数,则每个辅助构造函数必须使用 super 关键字来初始化基类型.

class MyView : View{    constructor (ctx : Context) : super(ctx)    constructor (ctx : Context,attrs : AttributeSet) : super(ctx , attrs)}

重载方法

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

Derived.v()需要覆盖(override)注释。 如果缺少(override)注释,编译器会抱错。 如果在一个函数上没有open注释,如在Base.nv()中,在子类中声明一个具有相同签名的方法是非法的,无论是否有覆盖(override)注释还是没有。 在final类(例如不使用open注释的类)中,则禁止覆盖成员。
标记为覆盖(override)的成员本身是打开的,即它可以在子类中被覆盖。 如果要禁止重新覆盖,请使用final关键字:

open class AnotherDerived() : Base() {    final override fun v() {}}

覆盖属性

覆盖属性的工作方式和覆盖方法类似,在超类上声明,在派生类上生命的属性,必须要用 override 来替代,必须具有兼容类型,每个声明的属性可被 具有初始化器或者 get,set方法覆盖

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

可以使用 var 属性覆盖 val 属性,反之也去可以,注意在主构造函数中使用override 关键字座位属性声明的一部分.

interface Foo {    val count: Int}class Bar1(override val count: Int) : Fooclass Bar2 : Foo {    override var count: Int = 0}

覆盖规则

kotlin中实现继承有以下规则控制:如果类从其直接超类继承同一成员的多个实现,则它必须覆盖该成员并提供自己的实现. 要表示从其集成的实现的超类型,可在尖括号內使用超类型名称超级限定,例 super

open class A {    open fun f() { print("A") }    fun a() { print("a") }}interface B {    fun f() { print("B") } // interface members are 'open' by default    fun b() { print("b") }}class C() : A(), B {    // The compiler requires f() to be overridden:    override fun f() {        super<A>.f() // call to A.f()        super<B>.f() // call to B.f()    }}

从B继承A 是没有问题的,对于a(),b()也没有问题,因为C只继承每个函数的实现,但是对于f()有两个继承的实现,因此必须在C()中重写f(),并提供消除歧义的实现.

抽象类

一个类和其一些成员可以被声明为抽象,抽象函数在其类中没有实现,请不要使用open来注释 抽象类和函数.可以用抽象来继承非抽象的open 成员~

open class Base {    open fun f() {}}abstract class Derived : Base() {    override abstract fun f()}

伴随对象

在kotlin中,类没有静态的概念(static),建议简单使用包级别的功能,如果需要编写一个可以调用的函数,而不需要一个类的实例,但需要去访问一个类的内部(例:工厂方法),可以将其作为一个对象声明来编写.

函数

     可以使用 fun 来定义:

fun onCreate(savedInstanceState: Bundle?) {    }

如果没有指定返回值 默认的返回的是 Unit,与java中的 void很相似,但 Unit 是个真正得对象,当然咱们也可以去指定他的返回值

fun sum(a:Int,b:Int):Int=a+b

构造方法和函数参数

    kotlin 的参数和java 的有所不同,我么是先写参数的名字 再写它的类型

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

    我们可以给参数指定一个默认值使得它们变得可选,这是非常有帮助的。这里有一
个例子,在Activity中创建了一个函数用来toast一段信息:

fun toast(message: String, length: Int = Toast.LENGTH_SHORT) {Toast.makeText(this, message, length).show()}

咱么在第二个参数中指定了一个默认值,这意味着你可以传或者不传,这样可以避免你需要的重载函数
toast(“hello world”)
toast(“hello world”,Toast.LENGTH_LONG)

fun niceToast(message: String,tag: String = javaClass<MainActivity>().getSimpleName(),length: Int = Toast.LENGTH_SHORT) {Toast.makeText(this, "[$className] $message", length).show()}

这个增加了一个参数 tag ,在java 中 总数的开销会很大.现在可以通过一下的方式调用:
toast(“Hello”)
toast(“Hello”, “MyTag”)
toast(“Hello”, “MyTag”, Toast.LENGTH_SHORT)
而且甚至还有其他的选择,通过参数名来调用,这表示你可以通过在值前 写明参数名来传入你想传的参数.
toast(message=”hello”,length=Toast.LENGTH_SHORT)
    温馨提示: 可以在模版中使用模版的表达式,在静态和变量的基础上 书写复杂的String,[className]message”, 如果这个表达式 有点复杂可以去用大括号括起来”Your name is
${user.name}”。

属性

在kolin 中,属性和java 中的字段是相同的,但是更加的强大,属性做的事情是字段上加上get 和set方法,下面是java中的代码片段,

public class Person {private String name;public String getName() {return name;} public void setName(String name) {this.name = name;}} ...Person person = new Person();person.setName("name");String name = person.getName();

在Kotlin中,只需要一个属性就可以了:

public class Person {var name: String = ""} ...val person = Person()person.name = "name"val name = person.name

如果没有任何的改变,那么属性会默认的使用getter和setter,当然它也可以修改为自定义的代码,并且不会修改存在的代码:

classs Person {var name: String = ""get() = field.toUpperCase()set(value){field = "Name: $value"}}

如果想要在getter和setter中访问这个属性自身的值,它需要 创建一个 backing field,可以使用这个 filed 预留字段来访问,它会被编译器找到正在使用的并自动创建,如果我们直接调用的属性,那么我们会直接调用 getter 和 setter 方法,而不是直接访问这个属性,backing field 只能在属性访问器內访问
当我们操作java代码的时候,kotlin将允许使用属性的语法去访问java中定义的getter 和setter所以在访问的时候不会有开销.