1、方法的定義:
fun sum(a: Int, b: Int): Int { // Int 參數a和b,返回值 Int
return a + b
}
//表達式作為函數體,返回類型自動推斷
fun sum(a: Int, b: Int) = a + b
public fun sum(a: Int, b: Int): Int = a + b // public 方法則必須明確寫出返回類型
fun printSum(a: Int, b: Int): Unit {
print(a + b)
}
//Unit相當于java中的void
// 如果是返回 Unit類型,則可以省略(對于public方法也是這樣):
public fun printSum(a: Int, b: Int) {
print(a + b)
}
可變長參數函數
fun vars(vararg v:Int){
for(vt in v){
print(vt)
}
}
// 測試
fun main(args: Array<String>) {
vars(1,2,3,4,5) // 輸出12345
}
lambda(匿名函數)
// 測試
fun main(args: Array<String>) {
val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
println(sumLambda(1,2)) // 輸出 3
}
2、常量與變量:
var和val的區別:
val:定義的變量是不可修改的(類似于java中的final)
var:定義的變量是可以修改的
常量與變量都可以沒有初始化值,但是在引用前必須初始化
編譯器支持自動類型判斷,即聲明時可以不指定類型,由編譯器判斷。
val a: Int = 1
val b = 1 // 系統自動推斷變量類型為Int
val c: Int // 如果不在聲明時初始化則必須提供變量類型
c = 1 // 明確賦值
var x = 5 // 系統自動推斷變量類型為Int
x += 1 // 變量可修改
3、NULL檢查機制:
代碼中可為空的參數,使用時需要進行空判斷處理,2種處理方式
1、字段后加!!像Java一樣拋出空異常
2、字段后加?可不做處理,返回值為 null或配合?:做空判斷處理
任何對象都分為可null和不可null,當對象可以為null時,使用的時候必須加判斷,或者加上!!
fun main(args: Array<String>) {
//類型后面加?表示可為空
var age: String? = "23"
//拋出空指針異常
val ages = age!!.toInt()
//不做處理返回 null
val ages1 = age?.toInt()
//age為空返回-1
val ages2 = age?.toInt() ?: -1
//-----------------------------------------------------------
//使用
val token = token()
//第一種方法
if (token != null) {//不加判斷會報錯
println(token.length)
//token?.length //如果token為null,則token?.length返回null,不會報錯
}
//第二種方法,當token為null時,會拋出空異常
//println(token!!.length)
}
//聲明返回值可以為null
fun token(): String? {
return null
}
4、類型檢測及自動類型轉換:
使用 is 運算符檢測一個表達式是否某類型的一個實例(類似于Java中的instanceof關鍵字)
fun getStringLength(obj: Any): Int? {
if (obj !is String)
return null
// 在這個分支中, `obj` 的類型會被自動轉換為 `String`
//---------------------------------------------------
// 在 `&&` 運算符的右側, `obj` 的類型會被自動轉換為 `String`
/* if (obj is String && obj.length > 0)
return obj.length*/
//---------------------------------------------------
return obj.length
}
5、區間:
區間表達式由具有操作符形式 .. 的 rangeTo 函數輔以 in 和 !in 形成
for (i in 1..4) print(i) // 輸出“1234”
for (i in 4..1) print(i) // 什么都不輸出
if (i in 1..10) { // 等同于 1 <= i && i <= 10
println(i)
}
// 使用 step 指定步長
for (i in 1..4 step 2) print(i) // 輸出“13”
for (i in 4 downTo 1 step 2) print(i) // 輸出“42”
// 使用 until 函數排除結束元素
for (i in 1 until 10) { // i in [1, 10) 排除了 10
println(i)
}
6、比較數字:
Kotlin 中,三個等號 === 表示比較對象地址,兩個 == 表示比較兩個值大小
fun main(args: Array<String>) {
val a: Int = 10000
println(a === a) // true,值相等,對象地址相等
//經過了裝箱,創建了兩個不同的對象
val boxedA: Int? = a
val anotherBoxedA: Int? = a
//雖然經過了裝箱,但是值是相等的,都是10000
println(boxedA === anotherBoxedA) // false,值相等,對象地址不一樣
println(boxedA == anotherBoxedA) // true,值相等
}
7、類型轉換:
val b: Byte = 1 // OK, 字面值是靜態檢測的
//al i: Int = b // 錯誤
val i: Int = b.toInt() // OK
toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char
8、數組:
數組的創建兩種方式:
1、一種是使用函數arrayOf()
2、另外一種是使用工廠函數。
fun main(args: Array<String>) {
//[1,2,3]
val a = arrayOf(1, 2, 3)
//[0,2,4]
val b = Array(3, { i -> (i * 2) })
//讀取數組內容
println(a[0]) // 輸出結果:1
println(b[1]) // 輸出結果:2
}
除了類Array,還有ByteArray, ShortArray, IntArray,用來表示各個類型的數組
9、字符串:
和 Java 一樣,String 是不可變的
var str = "1234";
for (c in str) {//遍歷打印字符串
println(c)
}
//----------------------------
val text = """
多行字符串
多行字符串
""".trimMargin()//去掉前置空格
10、條件控制:
fun main(args: Array<String>) {
var x = 0
if(x>0){
println("x 大于 0")
}else if(x==0){
println("x 等于 0")
}else{
println("x 小于 0")
}
var a = 1
var b = 2
val c = if (a>=b) a else b
println("c 的值為 $c")
}
使用區間
fun main(args: Array<String>) {
val x = 5
val y = 9
if (x in 1..8) {
println("x 在區間內")
}
}
11、When 表達式:
when 將它的參數和所有的分支條件順序比較,直到某個分支滿足條件。
when 既可以被當做表達式使用也可以被當做語句使用。
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // 注意這個塊
print("x 不是 1 ,也不是 2")
}
}
//----------------------------------------
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
//-----------------------------------------
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
//----------------------------------------------
fun hasPrefix(x: Any) = when(x) {
is String -> x.startsWith("prefix")
else -> false
}
//----------------------------------------------
//用來取代if-else if
when {
x.isOdd() -> print("x is odd")
x.isEven() -> print("x is even")
else -> print("x is funny")
}
在 when 中,else 等同 switch 的 default
12、循環控制:
For 循環
fun main(args: Array<String>) {
val items = listOf("apple", "banana", "kiwi")
for (item in items) {
println(item)
}
for (index in items.indices) {
println("item at $index is ${items[index]}")
}
}
while 與 do...while 循環
fun main(args: Array<String>) {
println("----while 使用-----")
var x = 5
while (x > 0) {
println( x--)
}
println("----do...while 使用-----")
var y = 5
do {
println(y--)
} while(y>0)
}
11、類的定義和類的屬性:
//constructor...主構造函數
//如果主構造器沒有任何注解,也沒有任何可見度修飾符,那么constructor關鍵字可以省略
class Person constructor(firstName: String) {
var name: String = "張三"
}
fun main(args: Array<String>) {
var person = Person("李四")//Kotlin 中沒有 new 關鍵字
println("姓名:" + person.name)
}
- getter 和 setter
getter 和 setter 都是可選
如果屬性類型可以從初始化語句或者類的成員函數中推斷出來,那就可以省去類型,val不允許設置setter函數,因為它是只讀的。
var allByDefault: Int? // 錯誤: 需要一個初始化語句, 默認實現了 getter 和 setter 方法
var initialized = 1 // 類型為 Int, 默認實現了 getter 和 setter
val simple: Int? // 類型為 Int ,默認實現 getter ,但必須在構造函數中初始化
val inferredType = 1 // 類型為 Int 類型,默認實現 getter
示例:
class Person {
var lastName: String = "zheng"
//當調用person.lastName,獲取值field.toUpperCase()
//field(后端變量) toUpperCase將變量賦值后轉換為大寫
get() = field.toUpperCase()
set//當調用person.lastName = "wang",觸發set
var no: Int = 100
get() = field
set(value) {//value當前傳遞過來的值,在賦值給field(后端變量)之前做一些操作改變值
if (value < 10) {
field = value //傳入的值小于10返回改值
} else {
field = -1 //如果傳入的值大于等于10 返回-1
}
}
var heiht: Float = 145.4f
private set//set方法為私有是,外部不可調
}
fun main(args: Array<String>) {
var person = Person()
person.lastName = "wang"http://將wang賦值給lastName
println("lastName:${person.lastName}")
person.no = 9
println("no:${person.no}")
}
- 輸出
lastName:WANG
no:9
Kotlin 中類不能有字段。提供了 Backing Fields(后端變量) 機制,備用字段使用field關鍵字聲明,field 關鍵詞只能用于屬性的訪問器
- 非空屬性必須在定義的時候初始化,kotlin提供了一種可以延遲初始化的方案,使用 lateinit 關鍵字描述屬性
class MyTest {
private lateinit var person: Person
fun setUp() {
person = Person("哇哈哈")
}
fun test() {
println(person.name)
}
}
fun main(args: Array<String>) {
val myTest=MyTest()
myTest.setUp()
myTest.test()
}
- 主構造器
主構造器中不能包含任何代碼,初始化代碼可以放在初始化代碼段中,初始化代碼段使用 init 關鍵字作為前綴
class Person constructor(firstName: String) {
init {
println("FirstName is $firstName")
}
}
構造器有注解,或者有可見度修飾符,這時constructor關鍵字是必須的,注解和修飾符要放在它之前。
- 次構造函數
需要加前綴 constructor
class MyTest(name: String="") {
var strName: String = ""
var age: Int = 0
init {
strName = name
}
//同一個類中代理另一個構造函數使用 this 關鍵字
constructor(name: String, age: Int) : this(name) {
strName = name
this.age = age
}
fun print() {
println("strName" + strName + "-----age" + age)
}
}
fun main(args: Array<String>) {
val myTest1 = MyTest("傳遞給次構造函數", 20)
myTest1.print()
val myTest2 = MyTest("傳遞給主造函數")
myTest2.print()
}
- 輸出
strName傳遞給次構造函數-----age20
strName傳遞給主造函數-----age0
如果一個非抽象類沒有聲明構造函數(主構造函數或次構造函數),它會產生一個沒有參數的構造函數。構造函數是 public 。如果你不想你的類有公共的構造函數,你就得聲明一個空的主構造函數:
class DontCreateMe private constructor () {
}
12、抽象類和嵌套類:
- 抽象類
open class Base {//open 標識此類可以被繼承
open fun f() {}
}
abstract class Derived : Base() {
override abstract fun f()
}
注意:無需對抽象類或抽象成員標注open注解
- 嵌套類
class Outer { // 外部類
private val bar: Int = 1
class Nested { // 嵌套類
fun foo() = 2
}
}
fun main(args: Array<String>) {
val demo = Outer.Nested().foo() // 調用格式:外部類.嵌套類.嵌套類方法/屬性
println(demo) // == 2
}
13、內部類和匿名內部類:
- 內部類
class Outer {
private val bar: Int = 1
var v = "成員屬性"
/**嵌套內部類**/
//類標記為inner,可以訪問外部類成員:
inner class Inner {
fun foo() = bar // 訪問外部類成員
fun innerTest() {
var o = this@Outer //獲取外部類的對象
println("內部類可以引用外部類的成員,例如:" + o.v)
}
}
}
fun main(args: Array<String>) {
val demo = Outer().Inner().foo()
println(demo) // 1
val demo2 = Outer().Inner().innerTest()
println(demo2) // 內部類可以引用外部類的成員,例如:成員屬性
}
要訪問來自外部作用域的 this,我們使用this@label,其中 @label 是一個 代指 this 來源的標簽
- 匿名內部類
class Test {
fun setInterFace(test: TestInterFace) {
test.test()
}
}
/**
* 定義接口
*/
interface TestInterFace {
fun test()
}
fun main(args: Array<String>) {
var test = Test()
/**
* 采用對象表達式來創建接口對象,即匿名內部類的實例。
*/
test.setInterFace(object : TestInterFace {
override fun test() {
println("對象表達式創建匿名內部類的實例")
}
})
}
14、類的修飾符:
- classModifier: 類屬性修飾符,標示類本身特性。
abstract // 抽象類
final // 類不可繼承,默認屬性
enum // 枚舉類
open // 類可繼承,類默認是final的
annotation // 注解類
- accessModifier: 訪問權限修飾符
private // 僅在同一個文件中可見
protected // 同一個文件中或子類可見
public // 所有調用的地方都可見
internal // 同一個模塊中可見
15、繼承:
Kotlin 中所有類都繼承該 Any 類,它是所有類的超類,對于沒有超類型聲明的類是默認超類
如果一個類要被繼承,可以使用 open 關鍵字進行修飾
open class Base(p: Int) // 定義基類
class Derived(p: Int) : Base(p)
- 子類有主構造函數
則基類必須在主構造函數中立即初始化
open class Person2(var name : String, var age : Int){// 基類
}
class Student(name : String, age : Int, var no : String, var score : Int) : Person2(name, age) {//子類
}
- 子類沒有主構造函數
則必須在每一個二級構造函數中用 super 關鍵字初始化基類,或者在代理另一個構造函數。初始化基類時,可以調用基類的不同構造方法。
class Student : Person {
constructor(ctx: Context) : super(ctx) {
}
constructor(ctx: Context, attrs: AttributeSet) : super(ctx,attrs) {
}
}
16、重寫:
在基類中,使用fun聲明函數時,此函數默認為final修飾,不能被子類重寫。如果允許子類重寫該函數,那么就要手動添加 open 修飾它, 子類重寫方法使用 override 關鍵詞:
/**用戶基類**/
open class Person{
open fun study(){ // 允許子類重寫
println("我畢業了")
}
}
/**子類繼承 Person 類**/
class Student : Person() {
override fun study(){ // 重寫方法
println("我在讀大學")
}
}
多個相同的方法(繼承或者實現自其他類,如A、B類),則必須要重寫該方法,使用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{
override fun f() {
super<A>.f()//調用 A.f()
super<B>.f()//調用 B.f()
}
}
fun main(args: Array<String>) {
val c = C()
c.f();
}
- 輸出
AB - 屬性重寫
使用 override 關鍵字,屬性必須具有兼容類型,每一個聲明的屬性都可以通過初始化程序或者getter方法被重寫:
interface Foo {
val count: Int
}
class Bar1(override val count: Int) : Foo
class Bar2 : Foo {
override var count: Int = 0
}