欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

kotlin语法分析(一)

程序员文章站 2022-06-20 18:28:09
...

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'
// 迭代String
val 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 String
val i = 23 // An Int
val actionBar = supportActionBar // An ActionBar in an Activity

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

val a: Any = 23
val 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) : Foo

class 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>().getSimpl
eName(),
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所以在访问的时候不会有开销.