其实官网文档很棒棒啊,http://www.kotlincn.net/docs/reference/android-overview.html
我为啥自己还要写个解释不全说不定还不准的渣文呢?好记性不如烂笔头啊
首先,Kotlin是运行在Jvm上的静态语言,源自Scala和java的结合,特性?
空类型安全、Lambda表达式、扩展方法、类型推导、没有分号、不需要new等等…
HelloWorld?
使用IDEA,可以直接新建kotlin的项目,选JVM的项目,一路next,新建一个kotlin文件,怎么写?
fun main(args:Array<out String>){
println("hello World!")
}这里的out可以省略,默认生成的也没有out
数据类:
data class Main(val id:Int,val name:String){}
//调用
printlin(Main(0,"name"))data class会直接将Main类toString覆写,所以上面的输出和ToString一样,构造方法在Main类后面的括号内
使用Gradle进行依赖管理
用IDEA新建一个Gradle项目

Java里可以直接访问kotlin的类,关于空指针,kotlin在编译时就会报错,java则会在运行时报错,解决办法是在构造参数的后面加上?号,就像这样
data class Main(val id:Int,val name:String?){}将Java代码复制到kt文件中IDE会自动提示转换代码, 但是转换出来的代码规范性和可读性都是没有那么好的。
java中自带反射的相关类,但是在kotlin中需要自己添加:
compile "org.jetbrains.kotlin:kotlin-reflect:1.2.20"
在代码中可以这样用
class HelloKotlin{
fun hello(){}
}
调用时
HelloKotlin::class.constructors.map(::println)
会输出构造函数的名字
集合遍历
上面的主函数,参数里那个out,是指泛型的extend,指继承者
.map{}是一个扩展方法,给所有可迭代的类型提供。比如Array、Collection
.map(::println)实际上是这样的,其传入的是一个lambda表达式
args.map{
println(it)
}
//上面也是这个意思
for (arg in args)
println(arg)这个it就是每个可迭代的项,::是指方法的引用,在java里是这样的
for(String arg:args){
System.out.println(arg);
}所以你应该明白了。
另外没有返回值返回的类型是Unit类型所以main方法可以这样
fun main(args:Array<out String>:Unit){
printlin("hello World!")
}扁平化集合flatmap
还是main方法
fun main(vararg args:String){
}这是可变参数vararg,Java中是 …
接下来从控制台输入点什么,比如A_B_C输出A B C,Java是这样写的
public static void main(String[] args) {
for (String a:args){
String[] splits=a.split("_");
for (String sp:splits){
System.out.println(sp);
System.out.println(" ");
}
}
}kotlin是这样的
fun main(vararg args:String){
args.flatMap {
it.split("_")
}.map {
print("$it ")
}
}split中传入的是正则哦,对比下应该就清楚kotlin是啥意思了,flatMap也是一个扩展方法,刚刚是不是提到控制台参数,估计还是有人不知道main怎么传参吧,上图

另外打印中的$是字符串模板,$it可以输出其值,当然你也可以输出一些属性值,不过得加上一些东西
比如${it.length}
关于flatMap,这个在java里也是有的,但是开头说到和Scala有点像是为什么呢?你可以看看这篇文章
你会发现 kotlin真的很像,但是写法上又更像java
枚举、When表达式
枚举:
enum class Lang{
ENGLISH,
CHINESE;
//伴生对象, 类和伴生对象是一一对应的
companion object {
//这里相当于一个静态方法
fun parse(name:String):Lang{
return Lang.valueOf(name.toUpperCase())
}
}
}用法?静态方法和枚举该怎么用就怎么用咯,main方法中传参
fun main(args: Array<String>): Unit {
if (args.size==0)return
val lang=Lang.parse(args[0]) //直接用 不new
println(lang) //不要封号
}提一提构造方法,控制台传入chinese
fun main(args: Array<out String>): Unit {
if (args.size==0)return
val lang=Lang.parse(args[0])
println(lang)
lang.sayHello()
}
enum class Lang(val hello:String){
ENGLISH("Hello"),
CHINESE("你好");
//var是变量 val是常量
var msg:String = ""
//伴生对象, 类和伴生对象是一一对应的
companion object {
//这里相当于一个静态方法
fun parse(name:String):Lang{
return Lang.valueOf(name.toUpperCase())
}
}
//构造方法的方法体
init {
//这里是可以访问到hello的
msg= hello;
}
fun sayHello(){
println(msg)
println(hello)
}
}输出都是一样的。
[扩展方法是一个重要的特性,可以不修改原始类,进行方法添加]如果想给Lang加上扩展方法呢?在普通方法前面加上类名.就好了
fun Lang.sayBye(){
}那么when怎么用?
fun describe(obj: Any): String =
val res=when (obj) {
1 -> "One"
"Hello" -> "Greeting"
is Long -> "Long"
!is String -> "Not a string"
else -> "Unknown"
}
println(res)从上可见,when可以匹配任意类型,并且是有返回值的,更多的看这里(超乎你想象的强大):
http://www.kotlincn.net/docs/reference/basic-syntax.html#using-when-expression
文件读取?
val text = File(ClassLoader.getSystemResource("input.txt").path).readText()就是这么简单
Retrofit2在kotlin中的使用
interface GitHubService{
@GET("https://api.github.com/repos/bboylin/UniversalToast/stargazers")
fun getStartGazers(): Call<List<User>>
}
data class User(val login:String,val id:Long,val avatar_url:String)
object Service{
val gitHubService:GitHubService by lazy {
Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://api.github.com")
.build().create(GitHubService::class.java)
}
}
fun main(args: Array<String>) {
Service.gitHubService.getStartGazers().execute()
.body()!!.map {
println(it)
}
}记得加上依赖
compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0'
噢,对了覆写方法应该怎样呢?
data class User(val login:String,val id:Long,val avatar_url:String){
override fun toString(): String {
return super.toString()
}
}其实差不多嘛,但是上面那个!!是啥呢?如果你去掉后,IDE会这样提示

查了下,是这个意思:
非空断言运算符( !! )将任何值转换为非空类型,若该值为空则抛出异常。
你可以写为?,然后意思是可以为空。用?号时为空的话,如果没数据,就输出空白,用!!则会是异常。
这是Kotlin的另外一个新特性,空安全
尾递归
/*原始方法 会栈溢出
fun factorail(num:Int): BigInteger {
if(num==0) return BigInteger.valueOf(1L);
return BigInteger.valueOf(num.toLong()).times(factorail(num-1))
}
fun main(args:Array<String>){
print(factorail(10000))
}
*/
/**
* BigInteger= BigInteger.valueOf(1L)是当不赋值时默认的空构造函数会初始化value为1
*/class Result(var value:BigInteger= BigInteger.valueOf(1L))
//tailrec是作为了一个标记符,加上后就会自动进行尾递归优化
tailrec fun factorial(num:Int,result: Result){
if(num==0)
result.value=result.value.times(BigInteger.valueOf(1L))
else{
result.value=result.value.times(BigInteger.valueOf(num.toLong()))
factorial(num-1,result)
}
}
/**
* val常量 var变量
*/fun main(args: Array<String>) {
val result=Result()
factorial(10000,result)
print(result.value)
}Kotlin中的单例模式
懒加载 线程不安全版 需要的时候再去初始化
class LazyNotThreadSafe {
//kotlin原版--------------------------------
companion object{
val instance by lazy(LazyThreadSafetyMode.NONE) {
LazyNotThreadSafe()
}
//JAVA翻译版--------------------------------
//下面是另一种等价的写法, 获取单例使用 get 方法
private var instance2: LazyNotThreadSafe? = null
fun get() : LazyNotThreadSafe {
if(instance2 == null){
instance2 = LazyNotThreadSafe()
}
return instance2!!
}
}
}java:

双重校验版 线程安全
class LazyThreadSafeDoubleCheck private constructor(){
//----------------原生版
companion object{
val instance by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED){
LazyThreadSafeDoubleCheck()
}
//-----JAVA翻译版
private @Volatile var instance2: LazyThreadSafeDoubleCheck? = null
fun get(): LazyThreadSafeDoubleCheck {
if(instance2 == null){
synchronized(this){
if(instance2 == null)
instance2 = LazyThreadSafeDoubleCheck()
}
}
return instance2!!
}
}
}java:

内部静态类 线程安全
class LazyThreadSafeStaticInnerObject private constructor(){
companion object{
fun getInstance() = Holder.instance
}
private object Holder{
val instance = LazyThreadSafeStaticInnerObject()
}
}java:

线程同步懒加载 线程安全 加同步锁,每次都会加锁,浪费资源
class LazyThreadSafeSynchronized private constructor() {
//伴生对象
companion object {
private var instance: LazyThreadSafeSynchronized? = null
@Synchronized
fun get(): LazyThreadSafeSynchronized{
if(instance == null) instance = LazyThreadSafeSynchronized()
return instance!!
}
}
}java:

懒人写法 类加载的时候初始化实例 会拖慢启动速度
object PlainOldSingleton {
}java里是这样的

新的枚举
密封类用来表示受限的类继承结构:当一个值为有限集中的类型、而不能有任何其他类型时。在某种意义上,他们是枚举类的扩展:枚举类型的值集合也是受限的,但每个枚举常量只存在一个实例,而密封类的一个子类可以有可包含状态的多个实例。
官方链接:http://www.kotlincn.net/docs/reference/sealed-classes.html
要声明一个密封类,需要在类名前面添加 sealed 修饰符。虽然密封类也可以有子类,但是所有子类都必须在与密封类自身相同的文件中声明。
扩展密封类子类的类(间接继承者)可以放在任何位置,而无需在同一个文件中。
//定义播放状态 枚举 每种类型只有一个实例
enum class State{
IDLE,PAUSED,PLAYING
}
//播放控制 sealed另外一种限定状态个数的办法
sealed class PlayerCmd{
//一个实例用object 多个用class
class Play(val url:String, val position:Long=0):PlayerCmd()
class Seek(val position:Long):PlayerCmd()
//因为没有参数所以用Obj就好了
object Pause:PlayerCmd()
object Resume:PlayerCmd()
object Stop:PlayerCmd()
}
//实现类 by
class Player {
//捕捉状态变化
private var state: State by Delegates.observable(State.IDLE, { prop, old, new ->
println("$old -> $new")
//?使得为空时不会执行
onPlayerStateChangedListener?.onStateChanged(old, new)
})
private fun sendCmd(cmd: PlayerCmd) {
when (cmd) {
is PlayerCmd.Play -> {
println("\nPlay ${cmd.url} from ${cmd.position}ms")
state = State.PLAYING
doPlay(cmd.url, cmd.position)
}
is PlayerCmd.Resume -> {
println("\nResume. ")
state = State.PLAYING
doResume()
}
is PlayerCmd.Pause -> {
println("\nPause. ")
state = State.PAUSED
doPause()
}
is PlayerCmd.Stop -> {
println("\nStop.")
state = State.IDLE
doStop()
}
is PlayerCmd.Seek -> {
println("\nSeek to ${cmd.position}ms, state: $state")
}
}
}
private fun doPlay(url: String, position: Long) {
TODO("Play function not yet implemented")
}
private fun doResume(){
//todo
}
private fun doPause() {
//todo
}
private fun doStop() {
//todo
}
//region api
interface OnPlayerStateChangedListener {
fun onStateChanged(oldState: State, new: State)
}
var onPlayerStateChangedListener: OnPlayerStateChangedListener? = null
fun play(url: String, position: Long = 0) {
sendCmd(PlayerCmd.Play(url, position))
}
fun resume() {
sendCmd(PlayerCmd.Resume)
}
fun pause() {
sendCmd(PlayerCmd.Pause)
}
fun stop() {
sendCmd(PlayerCmd.Stop)
}
fun seekTo(position: Long) {
sendCmd(PlayerCmd.Seek(position))
}
//endregion
}
fun main(args: Array<String>) {
val player: Player = Player()
player.play("http://xx.m4a")
player.pause()
player.resume()
player.seekTo(30000)
player.stop()
}泛型
http://www.kotlincn.net/docs/reference/generics.html
注解
说明:
http://www.kotlincn.net/docs/reference/annotations.html
使用:http://www.kotlincn.net/docs/reference/kapt.html
Java访问Kotlin
定义一个数据类
data class Person(var name:String)
然后在Java中调用:
public static void main(String[] args) {
Person person=new Person("name");
person.getName();
person.setName("other");
}如果改成
data class Person(var name:String,@JvmField var age:Int)
然后在Java中的时候age这种属性就没有了set、get了,因为@JvmField使得属性直接暴露出来了,同时该属性不能声明为private,并且不能自定义get set
单例?
object Singleton{
fun printlnHello(){
println("Hello")
}
}编译后看生成的字节码就会知道,已经帮你写好了单例模式,所以是可以直接用的
public static void main(String[] args) {
Singleton.INSTANCE.printlnHello();
}kotlin方法的默认参数
class Overloads{
fun oberloads(a:Int,b:Int=0,c:Int=1){
print("$a $b $c")
}
}在java中此时你是无法享受默认参数的便利的,需要这样改下
class Overloads{
@JvmOverloads
fun oberloads(a:Int,b:Int=0,c:Int=1){
print("$a $b $c")
}
}加上注解,就可以了
public static void main(String[] args) {
Overloads overloads = new Overloads();
overloads.oberloads(1);
}上图更直接

Kotlin可以将方法定义在包当中
Kotlin扩展方法的调用
fun String.isEmpty():Boolean{
return this!=""
}java中使用:编译后会以类文件名+Kt的方式去生成一个可直接调用的类
public static void main(String[] args) {
MainKt.isEmpty("");
}internal关键字
会使java无法访问到kotlin中被此关键字修饰的内容
Kotlin访问Java
korlin访问java中的类属性不再具有get/set,将只会显示属性
空安全问题:
fun main(args: Array<String>) {
val data = Data()
val s = data.value
println(s)
}java:
public class Data {
public String getValue(){
return null;
}
}此时直接输出null,如果给val s指定类型,比如val s:String=data.value,此时编译就会报错,此时value被称为平台类型,此时编译器会不care,大多数时候需要你自己判断定义,以及觉得加不加?号 还有 !!
泛型:java中的?变成了*,上下限变成了out in,java可选带泛型,kt必须有泛型参数,因此可能无限循环
Kotlin中Any就是Object
线程与同步:Kotlin中方法Synchronized变成了注解方式,代码块变成了方法,同时Volatile也变成了注解
最后,这个笔记实在是做不下去了,以上内容来自视频:
https://github.com/enbandari/Kotlin-Tutorials
其仓库中包含大量kotlin文章,以及其公众号的推送,值得一看,目测是鹅厂大佬
入门,应该大大概概差不多了,毕竟官方文档那么好,而且与java如此相似
本站广告由 Google AdSense 提供
0条评论