kotlin的基本用法详解

基本用法
1.常量和变量
使用val关键字声明一个常量(只读,不可修改),使用var关键字声明一个变量,下面是具体用法:

  1. fun test() {  
  2.     //使用val关键字声明一个常量(只读),声明常量时必须初始化  
  3.     val a: Int = 1 //显式指定常量的类型  
  4.     val b = 2  //自动推断类型  
  5.     val c: Int //声明一个不初始化的常量,必须显式指定类型  
  6. //    b = 3  //常量值不可修改,这句代码会报错  
  7.   
  8.     //a = 3  //不可以修改常量的值,此句代码会报错  
  9.   
  10.     //使用var关键字声明一个变量,变量的值可以修改  
  11.     var year: Int = 2016 //显式指定变量的类型  
  12.     var month = 5 //自动推断变量类型  
  13.     var day: Int //声明一个不初始化的变量,必须显式指定类型  
  14.     month = 6 //变量值可以被修改  
  15. }  

基本类型
对于java中我们都很清楚基本类型有 byteshortintlongdoublefloat、boolean、char 等,对于Kotlin中当然也有与其对应的,不过它们更像是java中的包装类 比如int->Integer ,Kotlin中是Int 
下面是对应关系(首字母变大写) 
- int->Int 
- double->Double 
- long->Long 
- double->Double 
- float->Float 
- boolean->Boolean 
- char->Char

Kotlin中使用接近于Java的方式(内置类型)来表示数字,但是又不完全相同,
比如没有隐式转换!Kotlin中数字相关的内置类型如下:


需要注意几点:
  ● 1.没有自动向上转型,比如Int转Long,需要自己调toXxx方法转


  ● 2.Long类型结尾必须为大写的L,不能为小写,比如1024L
  ● 3.字符Char不是Number,用单引号来声明,比如'c',不能像Java一样直接拿来当数字使,
如果你想把Char的值给Int,需要调toInt()方法
  ● 4.Boolean的值为truefalse5.Kotlin不支持8进制,十六进制0x开头,二进制0b开头
  ● 6.位运算符,Java中的与或运算符用:|和&,kotlin中使用or和and关键字来替代
其他运算符也有分别的关键字替代:shl(有符号左移),shr(有符号右移),ushr(无符号右移)
,xor(按位异或),inv(按位取反)
========================================================================================2、函数(方法)的使用
定义函数使用 fun 关键字,如下代码所示:

  1. fun add(a: Int, b: Int): Int {  
  2.     return a + b  
  3. }  
函数add有两个Int型的参数,冒号后跟的是函数的返回值,一条代码语句的末尾不用加分号,当然加上分号也没有问题。
上面的add函数还可以简写成如下形式:

  1. fun add(a: Int, b: Int) = a + b;  
没有显式指定函数的返回值,会自动推断函数的返回值。
如果一个函数没有返回值,可以写成如下两种形式:

  1. //没有返回值的函数,显式指定Unit为返回值  
  2. fun showAddResult(a: Int, b: Int): Unit {  
  3.     println(a + b)  
  4. }  
  5.   
  6. //没有返回值的函数,省略Unit的写法  
  7. fun showAddResult2(a: Int, b: Int) {  
  8.     println(a + b)  
  9. }  
=========================================================================

4、字符串模板

Kotlin允许在字符串中嵌入变量和表达式,只用在字符串内用 $ 符号开头,随后跟上输出变量的变量名即可,例如:
val name = "Bob"
println("My name is ${name}") //打印"My name is Bob"

val a = 10
val b = 20
println("The sum is ${a+b}") //打印"The sum is 30"

你也可以用下面的表达式:
val apples = 4
val bananas = 3

println("I have $apples apples and " + (apples + bananas) + " fruits.") // Java-esque
println("I have $apples apples and ${apples+bananas} fruits.") // Kotlin

//args 表示数组名称    Array<String>表示字符串类型的数组   ${args[0]} 表示数组中第0个元素的值
  1. //字符串模板的用法  t?
  2. fun stringTempl(args: Array<String>) {  
  3.     if(args.size > 0)  
  4.         println("args[0] = ${args[0]}")  
  5. }  
  6.   
  7. //main方法是整个程序的入口  
  8. fun main(args: Array<String>){  
  9.     var arr = arrayOf("hello", "world")  
  10.     stringTempl(arr)  
  11. }  
上面的代码执行后,在控制台打印如下内容:


我们来检查我们是否给 main 函数传递了参数。先来判断这个字符串数组是不是空,如果不为空,我们把第一个字符串分配给 name 变量。Kotlin 里有个 val 类型的声明方法,类似 Java 里的 final,也就是常量。
fun main(args: Array<String>) {
  val name = "World"
  if (args.isNotEmpty()) {
    name = args[0]
  }

  println("Hello, $name!")
}

在我们编译这个程序的时候,我们遇到一个问题:无法重新分配新的值给一个常量。一种解决方法是用内联的 if-else 方法。Kotlin 里的多数的代码块都支持返回值。如果语句进入了 if 代码块儿,也就是说 args 非空,那么就返回 arg[0],否则返回 “World”。 if-else 语句结束后,就直接赋值给我们之前声明的 name 常量,下面的例子就是条件赋值代码块:
fun main(args: Array<String>) {.
  val name = if (args.isNotEmpty()) {
    args[0]
  } else {
    "World"
  }

  println("Hello, $name!")
}

我们可以把上面的代码用一行来书写,看起来有点像 Java 里的三目运算符。移除掉那些大括号后,看起相当漂亮:
val name = if (args.isNotEmpty()) args[0] else "World"

然后kotlin还支持字符串遍历


======================================================================

5、条件表达式

区间表达式
你可能在其他的语言里见到过这样的表达式。的确, Kotlin 的不少特性是借鉴自其他语言里。下面这个表达式:如果 i 大于等于 1,并且小于等于 10,就将其打印出来。我们检测的范围是 110if (1 <= i && i <= 10) {
  println(i)
}

其实我们可以用 intRange 函数来完成这个操作。我们传入 110,然后调用 contains 函数来判断是否在这个范围里。我们打印出 i 即可。
if (IntRange(1, 10).contains(i)) {
  println(i)
}
这个还可以用扩展函数来实现,1.rangeTo 创建了一个 110 的 intRange,我们可以用 contain 来判断它。
更完美的而简洁的写法,是用下面的操作符:
if(i in 1..10) { ... }

.. 是 rangeTo 的一个别名,它实际背后工作原理还是 rangeTo。
我们还可遍历一个区间,比如:可以用 step 关键字来决定每次遍历时候的跳跃幅度:
for(i in 1..4 step 2) { ... }

也可以逆向迭代,或者逆向遍历并且控制每次的 step:
for (i in 4 downTo 1 step 2) { ... }

在 Kotlin 里,也可以结合不同的函数来实现你想要的区间遍历。可以遍历很多不同的数据类型,比如创建 strings 或者你自己的类型。只要符合逻辑就行。


常规的条件表达式可以是这么写的:
  1. //常规写法的条件表达式,这里的函数返回值不能省略  
  2. fun max(a: Int, b: Int): Int {  
  3.     if(a > b)  
  4.         return a  
  5.     else  
  6.         return b  
  7. }  
Kotlin可以简写条件表达式,如下所示:

  1. //简写的条件表达式  
  2. fun max2(a: Int, b: Int) = if(a > b) a else b  
==================================================================

6、可空类型
[plain] view plain copy
 print?
  1. fun nullableTest() {  
  2.     //在变量类型后面加上问号,代表该变量是可空变量  
  3.     var name: String? = "zhangsan"  
  4.     name = null //可以将null赋值给name变量  
  5.     var person: String = "tom"  
  6. //    person = null  //这句代码会报错,不可以将null赋值给一个不可空变量  
  7. }  
函数返回值为可空的例子如下代码:
[plain] view plain copy
 print?
  1. /*  
  2. 函数返回值为Int?,表示返回值可为空  
  3. 当参数为空或者为""时,则返回null,否则使用Java中的字符串转整型的方法  
  4. 这里也体现了kotlin代码和Java代码无缝集成  
  5.  */  
  6. fun parseInt(s: String): Int? {  
  7.     if(s == null || s == "")  
  8.         return null;  
  9.     return Integer.parseInt(s);  
  10. }  
===============================================================

7、类型检查和自动类型转换
Kotlin中使用is运算符来检查数据类型和做类型转换,如下代码所示:

  1. /*  
  2. 当函数参数为字符串类型时,就返回字符串的长度,否则返回空  
  3.  */  
  4. fun getStringLength(n: Any): Int? {  
  5.     if(n is String)  
  6.         return n.length //这里会自动将n转化为字符串类型  
  7.     return null  
  8. }  
上面的代码还可以写成:

  1. /*  
  2. 当函数参数为字符串类型时,就返回字符串的长度,否则返回空  
  3.  */  
  4. fun getStringLength(n: Any): Int? {  
  5.     if(n !is String)  
  6.         return null  
  7.     return n.length //这里会自动将n转化为字符串类型  
  8. }  
======================================================================

8for循环和while循环

  1. //for循环的测试代码  
  2. fun testFor() {  
  3.     var arr = arrayOf(1, 3, 4, 5, 6)  
  4.     for(i in arr.indices) { //通过索引循环  
  5.         println(arr[i])  
  6.     }  
  7.     for(num in arr) { //直接使用数组中的对象循环  
  8.         println(num)  
  9.     }  
  10. }  
  11.   
  12. //while循环的测试代码  
  13. fun testWhile() {  
  14.     var i = 0;  
  15.     while(i < 10) {  
  16.         print(" " + i)  
  17.         i++  
  18.     }  
  19. }  
=========================================================================

9、when表达式
when表达式就类似于Java中的switch表达式,如下代码所示:

  1. fun main(args: Array<String>) {  
  2.     testCase("hello world")  
  3. }  
  4.   
  5. fun testCase(obj: Any) {  
  6.     when(obj) {  
  7.         is String -> {  
  8.             print("this is string")  
  9.         }  
  10.         is Int -> {  
  11.             print("this is integer")  
  12.         }  
  13.         else -> {  
  14.             print("unkown value")  
  15.         }  
  16.     }  
  17. }  
==========================================================================

10、ranges的使用
(1)使用in操作符检查一个数是否在某个范围内

  1. /*  
  2. 判断分数是否大于等于90,小于等于100  
  3.  */  
  4. fun isGood(score: Int) {  
  5.     if(score in 90..100) //ranges是闭区间  
  6.         println("very good")  
  7.     else  
  8.         println("not so good")  
  9. }  
(2)检查索引是否越界

  1. /*  
  2. 检查index是否在数组arr的索引范围内  
  3.  */  
  4. fun checkIndex(index: Int, arr: Array<Int>) {  
  5.     if(index in 0..arr.lastIndex) //arr.lastIndex返回的是数组的最后一位的下标  
  6.         println("index in bounds")  
  7.     else  
  8.         println("index out of bounds")  
  9. }  
(3)遍历一个范围

  1. for(i in 1..5) {  
  2.     println(i)  
  3. }  
也可以通过in运算符遍历一个集合,如下代码:

  1. //in运算符遍历一个字符串数组  
  2. fun testStr(arr: Array<String>) {  
  3.     for(str in arr)  
  4.         println(str)  
  5. }  

=================================================================================

11、三元运算符

int length = a != null ? a.length() : -1
上面的代码你可能在 Java 里见到过。用三目运算符取值,检查是否为空,如果为空则返回真实的长度,否则返回 -1,Kotlin 里又相同的实现:
var length = if(a!= null) a.length() else -1

如果 a 不是 null, 那么就可以直接读值,否则返回默认值。这里用 elvis操作符 实现的简写:
var length = a?.length() ?: -1

我们用 ?号做了一个内联空检查。如果你还记得刚才我说的,如果 a 是 null,第一个 ?表达式就会返回 null ,如果 elivs 操作符 左侧是空,那么他就会返回右侧,否则直接返回左侧的值。

============================================

12、高阶函数
很多语言已经支持了高阶函数,比如 Java 8,但是你并不能用上 Java 8。如果你在用 Java 6 或者 Java 7,下面的例子实现了一个具有过滤功能的函数:
public interface Function<T, R> {
  R call(T t);
}

public static <T> List<T> filter(Collection<T> items, Function<T, Boolean> f) {
  final List<T> filtered = new ArrayList<T>();
  for (T item : items) if (f.call(item)) filtered.add(item);
  return filtered;
}

filter(numbers, new Function<Integer, Boolean>() {
  @Override
  public Boolean call(Integer value) {
    return value % 2 == 0;
  }
});
我们首先要声明一个函数接口,接受参数类型为 T,返回类型为 R。我们用接口中的方法遍历操作了目标集合,创建了一个新的列表,把符合条件的过滤了出来。
fun <T> filter(items: Collection<T>, f: (T) -> Boolean): List<T> {
  val filtered = arrayListOf<T>()
  for (item in items) if (f(item)) filtered.add(item)
  return filtered
}

上面的代码是在 Kotlin 下的实现,是不是简单很多?我们调用的时候如下:
kotlin filter(numbers, { value -> value % 2 == 0 })
你可能也发现了,我们没有定义任何的函数接口,这是因为在 Kotlin 中,函数也是一种数据类型。看到 f:(T) -> Boolean 这个语句了吗?这就是函数类型作为参数的写法,f 是函数别名,T是函数接受参数,Boolean 是这个函数的返回值。定义完成后,我们随后就能跟调用其他函数一样调用 f。调用 filter 的时候,我们是用 lambda 表达式来传入过滤函数的,即:{value ->value % 2 = 0}。
由于函数类型参数是可以通过函数声明的签名来推导的,所以其实还有下面的一种写法,大括号内就是第二个参数的函数体:
filter(numbers) {
  it % 2 == 0
}

=============================================================


13 .内联函数
内联函数和高阶函数经常一起见到。在某些场景下,当你用到泛型的时候,你可以给函数加上inline 关键字。在编译时,它会用 lambda 表达式替换掉整个函数,整个函数的代码会成为内联代码。
如果代码是这样的:
inline fun <T> filter(items: Collection<T>, f: (T) -> Boolean): List<T> {
  val filtered = arrayListOf<T>()
  for (item in items) if (f(item)) filtered.add(item)
  return filtered
}

filter(numbers) { it % 2 == 0 }

由 inline 关键字在编译后会变成如下这样:
val filtered = arrayListOf<T>()
for (item in items) if (it % 2 == 0) filtered.add(item)

这也意味着我们能实现一些常规函数实现不了的。比如:下面这个函数接受一个 lambda 表达式,但并不能直接返回:
fun call(f: () -> Unit) {
  f()
}

call {
  return // Not allowed
}

但是如果我们的函数变成内联函数,现在我们就能直接返回了,因为它是内联函数,会自动和其他代码混合在一起:
inline fun call(f: () -> Unit) {
  f()
}
call {
  return // Now allowed
}

内联函数也允许用 reified 类型。下面这个例子就是一个真实场景下的函数,通过一个 View 寻找类型为 T 的父元素:
inline fun <T : Any> View.findViewParent(): T? {
  var parent = getParent()
  while (parent != null && parent !is T) {
    parent = parent.getParent()
  }
  return parent as T // Cast warning
}

这个函数还有些问题。由于泛型类型被擦除了,所以我们无法检测类型,即便我们手工来做检查,依然会出现 warning。
解决方案是:我们给函数参数类型加上 reified 关键字。因为函数会被编译成内联代码,所以我们现在就能手工检查类型消除警告了:
inline fun <reified T : Any> View.findViewParent(): T? {
  var parent = getParent()
  while (parent != null && parent !is T) {
    parent = parent.getParent()
  }
  return parent as T // Type cast allowed
}
===========================================================================

14 .函数扩展

函数扩展是 Kotlin 最强大的特性之一。下面是一个工具函数,检测 App 是否运行在 Lollipop 或者更高的 Api 之上,它接受一个整数参数:
public fun isLollipopOrGreater(code: Int): Boolean {
  return code >= Build.VERSION_CODES.LOLLIPOP
}

通过 被扩展类型.函数 的写法,就能将函数变成被扩展类型的一部分,写法如下:
public fun Int.isLollipopOrGreater(): Boolean {
  return this >= Build.VERSION_CODES.LOLLIPOP
}

我们不在需要参数,想要在函数体内调用整数对象需要用 this 关键字。下面就是我们的调用方法,我们可以直接在整数类型上调用这个方法:
16.isLollipopOrGreater()


函数扩展可以是任何整形,字面量或者包装类型,也可以在标记为 final 的类上做类似操作。因为扩展函数不是真的给类增加代码,任何人都没有办法去修改一个类,它实际上是创建了一个静态方法,用语法糖来让扩展函数看着像是类自带的方法一样。
Kotlin 在 Java 集合中充分利用了扩展函数,这有一个例子操作集合:
final Function<Customer, Order> customerMapper = // ...
final Function<Order, Boolean> orderFilter = // ...
final Function<Order, Float> orderSorter = // ...
final List<Order> vipOrders = sortBy(filter(map(customers,
    customerMapper),
    orderFilter),
    orderSorter);

我们对一个 customer 集合,执行了 map, filter, 以及 sort 操作。嵌套的写法混乱而且难以阅读。下面是标准库的扩展函数写法,是不是简洁了很多:
val vipOrders = customers
    .map { it.lastOrder }
    .filter { it.total >= 500F }
    .sortBy { it.total }

=================================================================================



属性 (30:55)
Kotlin 把属性也变成了语言特性。
class Customer {
  private String firstName;
  private String lastName;
  private String email;

  public String getFirstName() { return firstName; }
  public String getLastName() { return lastName; }
  public String getEmail() { return email; }

  public void setFirstName(String firstName) { this.firstName = firstName }
  public void setLastName(String lastName) { this.lastName = lastName }
  public void setEmail(String email) { this.email = email }
}
上面是一个典型的 Java bean 类。可看到很多成员变量,和很多 getter, setter 方法,这可是只有三个属性的时候,就生成了这么多代码。来看看 Kotlin 的写法:
class Customer {
 var firstName: String = // ...
 var lastName: String = // ...
 var email: String = // ...
}

你只需要将成员变量定义成一个变量即可,默认是 public 的。编译器会自动生成 getter 和setter 方法。

主构造函数 (31:49)
Kotlin 中,类可以拥有多个构造函数,这一点跟 Java 类似。但你也可以有一个主构造函数。下面的例子是我们从上面的例子里衍生出来的,在函数头里添加了一个主构造函数:
在主构造函数里,可以直接用这些参数变量赋值给类的属性,或者用构造代码块来实现初始化。
class Customer(firstName: String, lastName: String, email: String) {
  var firstName: String
  var lastName: String
  var email: String

  init {
    this.firstName = firstName
    this.lastName = lastName
    this.email = email
  }
}

当然,更好的方法是:直接在主构造函数里定义这些属性,定义的方法是在参数名前加上 var或者 val 关键字,val 是代表属性是常量。
class Customer(
  var firstName: String,
  var lastName: String,
  var email: String)


单例 (35:53)
你可能经常会用到单例设计模式。比如一个 Logger 类,在 Java 里,有多种实现单例的写法。
在 Kotlin 里,你只要在 package 级别创建一个 object 即可!不论你在什么域里,你都可以像单例一样调用这个 objectobject Singleton

比如下面是一个 looger 的写法:
object Logger {
  val tag = "TAG"
  fun d(message: String) {
    Log.d(tag, message)
  }
}

你可以直接通过 Logger.D 的方法来调用 D 函数,它在任何地方都是可用的,而且始终只有一个实例。

Companion Objects (37:00)
Kotlin 移除了 static 的概念。通常用 companion object 来实现类似功能。你可能时常会看到一个 Activity 有一个 静态类型的 string,名叫 tag,和一个启动 Activity 的静态方法。Java 中的实现如下:
class LaunchActivity extends AppCompatActivity {
  public static final String TAG = LaunchActivity.class.getName();

  public static void start(Context context) {
    context.startActivity(new Intent(context, LaunchActivity.class));
  }
}
在 Kotlin 下的实现如下:
class LaunchActivity {
  companion object {
    val TAG: String = LaunchActivity::class.simpleName

    fun start(context: Context) {
      context.startActivity(Intent(context, LaunchActivity::class))
    }
  }
}

Timber.v("Starting activity ${LaunchActivity.TAG}")

LaunchActivity.start(context)

有了 companion object 后,就跟类多了一个单例的对象和方法一样。

类委托 (37:58)
委托是一个大家都知道的设计模式,Kotlin 把委托视为很重要的语言特性。下面是一个在 Java 中典型的委托写法:
public class MyList<E> implements List<E> {
  private List<E> delegate;

  public MyList(List<E> delegate) {
    this.delegate = delegate;
  }

 // ...

  public E get(int location) {
    return delegate.get(location)
  }

  // ...
}
我们有一个自己的 lists 实现,通过构造函数将一个 list 存储起来,存在内部的成员变量里,然后在调用相关方法的时候再委托给这个内部变量。下面是在 Kotlin 里的实现:
class MyList<E>(list: List<E>) : List<E> by list

用 by 关键字,我们实现了一个存储 E 类型的 list,在调用 List 相关的方法时,会自动委托到 list 上。
译者注:参考 Kotlin 官方文档了解更多。

声明点变型(Declaration-Site Variance) (39:03)
这个可能是一个比较容易让人迷惑的主题。首先,我们用一个协变数组来开始我们的例子,下面的代码能够很好的编译:
String[] strings = { "hello", "world" };
Object[] objects = strings;
string 数组可以正常的赋值给一个 object 数组。但是下面的不行:
List<String> strings = Arrays.asList("hello", "world");
List<Object> objects = strings;
你不能分配一个 string 类型的 list 给一个 object 类型的 list。因为 list 之间是没有继承关系的。如果你编译这个代码,会得到一个类型不兼容的错误。想要修复这个错误,我们得用到 Java 中的点变型(use-site variance)去声明,所谓的点变型就是在声明 list 可接受类型的时候,用extends 关键字给出参数类型的可接受类型范围,比如类似如下的例子:
译者注:点变型只是一个名字,不要太在意为什么叫这个,简单理解就是类似通配符原理,具体可以查看这个维基页面。
public interface List<E> extends Collection<E> {
  public boolean addAll(Collection<? extends E> collection);
  public E get(int location);
}
addAll 方法可以接受一个参数,参数类型为所有继承自 E 的类型,这不是一个具体类型,而是一个类型范围。每次调用 get 方法时,依然返回类型 E。在 Kotlin 中,你可以用 out 关键字来实现类似的功能:
public interface List<out E> : Collection<E> {
  public fun get(index: Int): E
}

public interface MutableList<E> : List<E>, MutableCollection<E> {
  override fun addAll(c: Collection<E>): Boolean
}

上面的一系列被称为声明点变型,即在声明可接受参数的时候,就声明为它是可变的。比如上面例子:我们声明参数是可以允许所有继承自 E 类型的,返回类型也为 E 的。
现在,我们有了可变和不可变类型的列表。可变性(variance) 其实很简单,就是取决于我们在声明的时候是动作。
译者注:其实不论声明点变型(Declaration-Site Variance) 还是 点变型(Use-site variance) 都是为了实现泛型的类型声明,标注泛型类型可支持的范围,厘清泛型类型上下继承边界。参考Generic Types。

操作符重载 (41:26)
enum class Coin(val cents: Int) {
  PENNY(1),
  NICKEL(5),
  DIME(10),
  QUARTER(25),
}

class Purse(var amount: Float) {
  fun plusAssign(coin: Coin): Unit {
    amount += (coin.cents / 100f)
  }
}

var purse = Purse(1.50f)
purse += Coin.QUARTER // 1.75
purse += Coin.DIME // 1.85
purse += Coin.PENNY // 1.86

上面的代码中,我们创建了一个硬币枚举,每个硬币枚举都代表一个特定数额的硬币。我们有一个 Purse(钱包) 类, 它拥有一个 amount 成员变量,代表钱包里现在有多少钱。我们创建了一个叫做 plusAssign 的函数,plusAssign 是一个保留关键字。这个函数会重载 += 操作符,也就是说当你在调用 += 符号的时候,就会调用这个函数。
随后,创建一个 purse 实例,可以直接用 += 操作来实现给钱包里放钱进去。


============================================================
创建bean类

class Person{
    var name: String = ""
    var age: Int = 0
    var college: String? = null
}

声明变量必须使用关键字var,而如果要创建一个只读/只赋值一次的变量,则需要使用val代替它
在上述代码中,变量name和age不可为空,而?表明变量college可以为空

创建实例

var jake = Person()
注意,Kotlin没有关键字new。 实例创建完成后,就可以像在Java中一样为变量赋值了:
1.直接赋值
jake.name = "Jake Hill"
jake.age = 24
jake.college = "Stephen's College"

2.通过构造函数赋值
class Person(var name: String, var age: Int, var college: String?) {
}

由于构造函数中没有其它操作,所以花括号也可以省略
class Person(var name: String, var age: Int, var college: String?)

var jake = Person("Jake Hill", 24, "Stephen's College")

上述代码中的构造函数是类头的一部分,称为主构造函数。在Kotlin中,还可以使用constructor关键字创建辅助构造函数,例如,下面的代码增加了一个辅助构造函数初始化变量email:
class Person(var name: String, var age: Int, var college: String?) {
    var email: String = ""
    constructor(name:String, age:Int, college: String?, email: String) : this(name, age, college) {
        this.email = email
    }
}

Kotlin允许创建派生类,但要遵循如下规则:
  ● 必须使用:代替Java中的extends关键字
  ● 基类头必须有open注解
  ● 基类必须有一个带参数的构造函数,派生类要在它自己的头中初始化那些参数
比如下面的代码创建了一个名为Empoyee的派生类:
open class Person(var name: String, var age: Int, var college: String?) {
    ...
}

class Employee(name: String, age: Int, college: String?, var company: String) : Person(name, age, college) {
}

======================================================

函数与扩展
有派生就有重载。与类的派生一样,允许重载的方法要有open注解,而在派生类中重载时要使用override注解。例如,下面是在Employee类中重载Person类的isEligibleToVote方法的代码:

override fun isEligibleToVote(): Boolean {
    return true
}

除了改变类的已有行为,Kotlin还允许开发者在不修改类的原始定义的情况下实现对类的扩展,如下面的代码为Person类增加了一个名为isTeenager的扩展:

fun Person.isTeenager(): Boolean {
    return age in 13..19
}

上面提到的函数都与Java中的函数类似,但Kotlin还支持其它类型的函数。如果一个函数返回单个表达式的值,那么可以使用=来定义函数。下面是一个创建单表达式函数的例子:
fun isOctogenarian(): Boolean = age in 80 .. 89

Kotlin还支持高阶函数和Lambda表达式。例如,lambda表达式{x,y->x+y}可以像下面这样给一个变量赋值:
val sumLambda: (Int, Int) -> Int = {x,y -> x+y}

而下面的高阶函数将上述表达式作为一个参数,并将表达式的计算结果翻倍:
fun doubleTheResult(x:Int, y:Int, f:(Int, Int)->Int): Int {
    return f(x,y) * 2
}
该函数可以使用下面的其中一种方式调用:
val result1 = doubleTheResult(3, 4, sumLambda)

或
val result2 = doubleTheResult(3, 4, {x,y -> x+y})

================================================================

范围表达式
在Kotlin中,范围表达式用的比较多。范围创建只需要..操作符,例如:
val r1 = 1..5
//该范围包含数值1,2,3,4,5

如果创建一个降序范围,则需要使用downTo函数,例如:
val r2 = 5 downTo 1
//该范围包含数值5,4,3,2,1

如果步长不是1,则需要使用step函数,例如:
val r3 = 5 downTo 1 step 2
//该范围包含数值5,3,1

===============================================================

条件结构
在Kotlin中,if是一个表达式,根据条件是否满足返回不同的值,例如,下面的代码将isEligibleToVote设置为“Yes”
var age = 20
val isEligibleToVote = if(age > 18) "Yes" else "No"

when表达式相当于Java的switch,但功能更强大,例如,下面的代码将typeOfPerson设置为“Teenager”:
val age = 17

val typeOfPerson = when(age){
    0 -> "New born"
    in 1..12 -> "Child"
    in 13..19 -> "Teenager"
    else -> "Adult"
}

==============================================================

循环结构
Kotlin使用for..in遍历数组、集合及其它提供了迭代器的数据结构,语法同Java几乎完全相同,只是用in操作符取代了:操作符,例如,下面的代码将遍历一个String对象数组:
val names = arrayOf("Jake", "Jill", "Ashley", "Bill")

for (name in names) {
    println(name)
}

whiledo..while循环的语法与Java完全相同。

==========================================================================

 枚举 enum 类。

类语法 (5:19)
我们来看看类。类的定义要通过 class 关键字,跟 Java 里的一样,关键字后是类名。Kotlin 有一个主构造函数,我们可以直接将构造函数参数列表写在类的声明处,还可以直接用 var 或者 val关键字将参数声明为成员变量(又称:类属性),如下:
class Person(var name: String)

继续之前的例子,有了主构造函数以后,我们就不再需要成员变量赋值语句了。在 Kotlin 里创建实例的时候,不必使用 new 关键字。你只需要指明创建的类型名就可以创建实例了。
class Person(var name: String)

fun main(args: Array<String>) {
  val person = Person("Michael")
  println("Hello, $name!")
}

很容易发现,字符串插值实际上是错误的,因为 name 指向的是一个不存在的变量了。我们可以用刚才提到的 字符串插值表达式 ,即用 $ 符号和大括号包裹想要插入的变量,来修复这个问题:
class Person(var name: String)

fun main(args: Array<String>) {
  val person = Person("Michael")
  println("Hello, ${person.name}!")
}

下面是 enum 类。枚举跟 Java 里的枚举很像。定义一个枚举的方法如下:
enum class Language(val greeting: String) {
  EN("Hello"), ES("Hola"), FR("Bonjour")
}

我们来给 Person 类增加一个叫 lang 的属性,代表一个人的所说的语言。
class Person(var name: String, var lang: Language = Language.EN)

Kotlin 支持参数默认值,如上:language 的默认值就是 Language.EN,这样就可以在创建实例的时候忽略这个参数,除非你要改变 language 的属性值。我们来把这个例子变得更面向对象一些,给 person 增加一个打招呼的方法,简单地输出特定语言打招呼的方法还有人名:
enum class Language(val greeting: String) {
  EN("Hello"), ES("Hola"), FR("Bonjour")
}

class Person(var name: String, var lang: Language = Language.EN) {
  fun greet() = println("${lang.greeting}, $name!")
}

fun main(args: Array<String>) {
  val person = Person("Michael")
  person.greet()
}

现在在 main 函数里调用 person.greet() 方法,看看是不是很酷?!

集合和迭代 (11:32)
val people = listOf(
  Person("Michael"),
  Person("Miguel", Language.SP),
  Person("Michelle", Language.FR)
)

我们可以用标准库函数 listOf 方法创建一个 person 列表。遍历这些 person 可以用 for-in 关键字:
for (person in people) {
  person.greet()
}

随后,我们可以在每次遍历的时候执行 person.greet() 方法,甚至可以更简单,直接调用 people 集合的扩展方法 forEach,传入一个 lambda 表达式,在表达式里用 it 代表每次遍历到的person 对象,然后调用它们的 greet 方法。
people.forEach { it.greet() }

我们来创建两个新的类,每个都传入一个默认的语系。我们可以不再像刚才那样重复声明,可以直接用继承的方法来实现。下面是一个扩展版本的 Hello World。展示了很多 Kotlin 的特性:
enum class Language(val greeting: String) {
  EN("Hello"), ES("Hola"), FR("Bonjour")
}

open class Person(var name: String, var lang: Language = Language.EN) {
  fun greet() = println("${lang.greeting}, $name!")
}

class Hispanophone(name: String) : Person(name, Language.ES)
class Francophone(name: String) : Person(name, Language.FR)

fun main(args: Array<String>) {
  listOf(
    Person("Michael"),
    Hispanophone("Miguel"),
    Francophone("Michelle")
  ).forEach { it.greet() }
}
===============================================================================

项目效果展示apk : http://imtt.dd.qq.com/16891/670C11ECFEA442BE99BACA612A7EA798.apk?fsname=com.ycjt.ycnyzx_1.0.1_1.apk&csr=1bbd

或 : http://android.myapp.com/myapp/detail.htm?apkName=com.ycjt.ycnyzx

安卓开发交流群 : 595856941

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值