kotlin语法分析(一)
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,[
${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所以在访问的时候不会有开销.