Kotlin
概述
Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,由 JetBrains 设计开发并开源。Kotlin 可以编译成Java字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。在Google I/O 2017中,Google 宣布 Kotlin 成为Android 官方开发语言。Android Studio 3.0 已经自带Kotlin的插件。
谷歌和 JetBrains 将为 Kotlin 成立一个非盈利基金会。Kotlin 语言的开发,还是 JB 为主导。
基本语法
Kotlin 的基本数值类型包括 Byte、Short、Int、Long、Float、Double、Boolean 等。不同于Java的是,字符不属于数值类型,是一个独立的数据类型。
Int到底是什么?
fun main(args: Array<String>) {
//final 反编译
val i = 10 //val 可以理解为java的final 变量
var j: Int? = null
var c = '1'
}
class反编译为Java
public static final void main(@NotNull String[] args)
{
Intrinsics.checkParameterIsNotNull(args, "args");
int i = 10;
Integer j = (Integer)null;
char c = '1';
}
条件循环语句
var a = 10
var result: Int = if (a > 10) 100 else 1000
result = when(a) {//when 代替 switch
1 -> 100
2 -> {
100 + 1000
}
else -> {
1 + 2
}
}
val items = listOf("apple", "banana", "kiwi")
for (item in items) {
println(item)
}
for (i in 1..100) {
println(i)
}
类的定义
//定义一个Person类,可以在构造方法里定义成员变量
//?代表变量可null
class Person(val name: String?, val age: Int?)
//定义一个空类
class Person
//私有构造方法 参数默认值
open class Person(name: String? = "lisi", age: Int? = 10) {
//次构造函数
constructor(name: String?, age: Int?, id: String): this(name, age) {
this.id = id
}
//初始化
init {
//......
}
var name = name
get() = name + "tail"
set(value) {
field = "header" + value
}
var age = age
var id: String? = null
inner class Sutdent2 {
init {
println(name)//读取外部类的成员
}
}
class Student {//嵌套类
init {
//println(name) 嵌套类对外部类this没有引用 不能读取成员变量
}
}
}
data数据类
data类型的类会帮你自动生成equals、hashCode、toString、copy方法
fun main(args: Array<String>) {
var comment = Comment("zhangsan", "123456")
var comment2 = Comment("lisi", "654321")
println(comment.toString())
println(comment.equals(comment2))
//fun copy(name: String = this.name, commentId: String = this.commentId) = Comment(name, commentId) //copy原型
var comment3 = comment.copy("wangwu")
println(comment3)
}
data class Comment(var name: String, var commentId: String)
classModifier: 类属性修饰符,标示类本身特性:
- abstract // 抽象类
- final // 类不可继承,默认属性
- enum // 枚举类
- open // 类可继承,类默认是final的
- annotation // 注解类
accessModifier: 访问权限修饰符:
- private // 仅在同一个文件中可见
- protected // 同一个文件中或子类可见
- public // 所有调用的地方都可见
- internal // 同一个模块中可见
object类
单例模式
fun main(args: Array<String>) {
SingleTest.println()
}
object SingleTest{
fun println() {
println("SingleTest")
}
}
以下为class反编译的java代码
public static final void main(@NotNull String[] args)
{
Intrinsics.checkParameterIsNotNull(args, "args");
SingleTest.INSTANCE.println();
}
public final class SingleTest
{
public static final SingleTest INSTANCE;
static
{
new SingleTest();
}
private SingleTest()
{
INSTANCE = (SingleTest)this;
}
public final void println()
{
String str = "SingleTest2";System.out.println(str);
}
}
单例延迟创建对象,companion object处理静态方法和常量
fun main(args: Array<String>) {
SingleTest.instance.println()
SingleTest.staticFunction()
}
class SingleTest private constructor() {
companion object {
//定义常量
const val EVENT_INIT = "123"
val instance: SingleTest by lazy {
SingleTest()
}
//类似静态方法
fun staticFunction() {
println("staticFunction")
}
}
fun println() {
println("SingleTest")
}
}
class反编译为Java
public static final void main(@NotNull String[] args)
{
Intrinsics.checkParameterIsNotNull(args, "args");
SingleTest.Companion.getInstance().println();
SingleTest.Companion.staticFunction();
}
public final class SingleTest {
public static final Companion Companion = new Companion(null);
@NotNull
public static final String EVENT_INIT = "123";
@NotNull
private static final Lazy instance$delegate = LazyKt.lazy((Function0)SingleTest2.Companion.instance.2.INSTANCE);
public static
final class Companion {
@NotNull
public final SingleTest getInstance()
{
Lazy localLazy = SingleTest . access $getInstance$cp();
Companion localCompanion = this;
KProperty localKProperty = $$delegatedProperties[0];
return (SingleTest2) localLazy . getValue ();
}
public final void staticFunction()
{
String str = "staticFunction";
System.out.println(str);
}
}
public final void println()
{
String str = "SingleTest";
System.out.println(str);
}
}
静态方法和常量完全可以只使用普通函数和const关键字
//Constans.kt 文件
package com.vmovier.promise3.test
const val EVENT_INIT = 1
//Utils.kt 文件
package com.vmovier.promise3.test
import java.text.SimpleDateFormat
import java.util.*
fun formatDate(millTime: Long) {
var format = SimpleDateFormat("yyyy-MM-dd")
val date = format.format(Date(millTime))
println(date)
}
//test.kt 文件
fun main(args: Array<String>) {
println(EVENT_INIT)
formatDate(100000)
}
泛型
协变
Java协变
public static void main(String[] args) {
//java编译器并不认为
//ArrayList<String>是ArrayList<Object>的子类
//下面的代码不能通过编译
ArrayList<Object> list = new ArrayList<String>();
//,在java里这两个类没有任何关系,如果让它们有关系可
//以使用通配符
ArrayList<? extends Object> list = new ArrayList<String>();
}
Kotlin协变、逆变,Kotlin支持声明点协变,
在定义泛型类VideoDetail<out T>
时,当我们在泛型类型T前面添加out,VideoDetail为T的协变类。在该类的作用域内,类型T只能作为该类中函数的返回类型,不能作为参数传递进来,这时也称做VideoDetail为T的生产者(Producer)。
以此类推,在定义泛型类AlbumDetail<in T>
时,当我们在泛型类型T前面添加in,AlbumDetail为T的逆变类。在该类的作用域内,类型T只能作为该类中函数的参数传递进来,不能作为返回类型,这时也称做AlbumDetail为T的消费者(Consumer)。
fun main(args: Array<String>) {
var video: VideoDetail<Any> = VideoDetail<String>()
video.modifyData(123)
println((video.data as String).length)
var album: AlbumDetail<String> = AlbumDetail<Any>()
println(album.data?.length)
}
class VideoDetail<out T> (var data: @UnsafeVariance T? = null) {
fun modifyData(data: @UnsafeVariance T?) {
println(data is String)
this.data = data
}
}
class AlbumDetail<in T> (var data: @UnsafeVariance T? = null)
泛型边界
java
public class VideoDetail<T extends Object> {
private T data;
}
kotlin
class AlbumDetail<T: Any> (var data: T? = null)
空安全
var str: String? = null
var len: Int? = str?.length
println("len : " + len)
var len2 = str!!.length//如果str为null 则抛出KotlinNullPointerException
//类型转换安全 如果a 不是Int类型 则返回ull
val aInt: Int? = a as? Int
相等判断
a === b 只有当a和b指向同一个对象才返回true。
a == b 会使用equals进行比较,一般翻译为:a?.equals(b) ?: (b === null)
lambda与函数类型
fun main(args: Array<String>) {
var f: (Int, Int) -> String//定义一个函数类型的变量
//lambda
f = { a: Int, b: Int ->
(a + b).toString()
}
println(f(1, 2))//打印 3
f = fun(a: Int, b: Int): String {
return (a * b).toString()
}
println(f(2, 8))//打印 16
f = ::function
println(f(3, 1))//打印 2
}
fun function(a: Int, b: Int): String {
return (a - b).toString()
}
委托
委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。
Kotlin 直接支持委托模式,更加优雅,简洁。Kotlin 通过关键字 by 实现委托。
interface Base {
fun print(msg: String)
}
class Delegate: Base {
override fun print(msg: String) {
println("Delegate: " + msg)
}
}
class Person(delegate: Base): Base by delegate
//test
var p = Person(Delegate())
p.print("test")
//打印结果: Delegate: test
属性委托
class Example {
var p: String by Delegate()
}
// 委托的类
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, 这里委托了 ${property.name} 属性"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$thisRef 的 ${property.name} 属性赋值为 $value")
}
}
fun main(args: Array<String>) {
val e = Example()
println(e.p) // 访问该属性,调用 getValue() 函数
e.p = "Runoob" // 调用 setValue() 函数
println(e.p)
}
延迟属性 Lazy
lazy() 是一个函数, 接受一个 Lambda 表达式作为参数, 返回一个 Lazy <T>
实例的函数,返回的实例可以作为实现延迟属性的委托: 第一次调用 get() 会执行已传递给 lazy() 的 lamda 表达式并记录结果, 后续调用 get() 只是返回记录的结果。
fun main(args: Array<String>) {
var demo = Demo()
println(demo.str)
println(demo.str)
}
class Demo {
val str: String by lazy{
println("init")
"Hello"
}
}
//打印结果
/**
init
Hello
Hello
*/
可观察属性 Observable
observable 可以用于实现观察者模式。
Delegates.observable() 函数接受两个参数: 第一个是初始化值, 第二个是属性值变化事件的响应器(handler)。
在属性赋值后会执行事件的响应器(handler),它有三个参数:被赋值的属性、旧值和新值:
fun main(args: Array<String>) {
var demo = Demo()
demo.name = "zhangsan"
demo.name = "lisi"
}
class Demo {
var name: String by Delegates.observable("init value"){
prop, old, new ->
println("旧值:$old 新值: $new")
}
}
//打印结果
/**
旧值:init value 新值: zhangsan
旧值:zhangsan 新值: lisi
*/
集合
fun main(args: Array<String>) {
//可变集合
var mutableList: MutableList<String> = mutableListOf("1", "2", "3")
mutableList.add("4")
println(mutableList)
var mutableSet: MutableSet<String> = mutableSetOf("1", "2", "3")
mutableSet.add("4")
println(mutableSet)
var mutableMap: MutableMap<String, String> = mutableMapOf("a" to "1", "b" to "2", "c" to "3")
mutableMap.put("d", "4")
println(mutableMap)
//不可变集合
var list: List<String> = listOf("1", "2", "3")
//list.add("4") //编译报错 没有这个方法
println(list)
//遍历
list.forEach { println(it) }
var map:Map<String, String> = mapOf("a" to "1", "b" to "2", "c" to "3")
//map.put("d", "4")//编译报错 没有这个方法
println(map)
var arrayList = ArrayList<String>()
arrayList.add("1")
arrayList.add("2")
arrayList.add("3")
println(arrayList)
var map2 = HashMap<String, String>()
map2.put("a", "1")
println(map2)
var set2 = TreeSet<String>()
set2.add("1")
set2.add("2")
set2.add("3")
println(set2)
}
扩展
Kotlin和c#、Gosu一样,能够扩展一个类的新功能,而无需继承类或使用任何类型的设计模式,如装饰者。
fun MutableList<String>.swap(index1: Int, index2: Int) {
val tmp = this[index1]
this[index1] = this[index2]
this[index2] = tmp
}
fun main(args: Array<String>) {
var mutableList: MutableList<String> = mutableListOf("1", "2", "3")
mutableList.add("4")
println(mutableList)
mutableList.swap(0, 1)
println(mutableList)
}
扩展的静态解析
扩展不能真正的修改他们继承的类。通过定义一个扩展,你不能在类内插入新成员, 仅仅是通过该类的实例用点表达式去调用这个新函数。
fun main(args: Array<String>) {
var stu = Student()
log(stu)
var person = BasePerson()
println(person.log())
}
open class BasePerson {
var name: String? = null
var age: Int? = null
fun log() = "log"
}
class Student: BasePerson() {
var number: Int? = null
}
fun BasePerson.get() = "BasePerson"
fun Student.get() = "student"
fun BasePerson.log() = this.toString()
fun log(obj: BasePerson) {
println(obj.get())
}
Android开发
class MainActivity : AppCompatActivity() {
companion object {
// const val TAG: String? = MainActivity::class.simpleName
const val TAG = "MainActivity"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//id 是 textView
textView.text = "hello"
//如果lamda 参数只有一个可以省略
textView.setOnClickListener {
Log.i(TAG, "it : " + it)
}
val textview1 = find<TextView>(R.id.textView)
textview1.text = "hello2"
toast("toast")
longToast("longToast")
//子线程任务
async {
Log.i(TAG, "thread name:" + Thread.currentThread().name)
//主线程
uiThread {
Log.i(TAG, "thread name:" + Thread.currentThread().name)
}
}
}
}