前言

本章我们将学习怎么用kotlin声明任何程序都存在的基本要素:变量、函数、类以及属性的概念

一、函数和变量

1.1 Hello World

让我们以一个经典的例子开始:打印“Hello, world!”

fun main(args: Array<String>) { println("Hello, world!")
}

从上面代码我们能看到哪些特点呢?

  • 关键字fun用来声明一个函数。(没错,kotlin就是这么fun)
  • 参数类写在参数名字的后面,变量的声明也是如此。
  • 函数可以在文件的最上层中声明,你没必要把它放到一个类中。
  • 数组就是类。不像Java,Kotlin没有特定的声明数组的语法。
  • 用println,而不是System.out.println。Kotlin标准库提供了很多标准Java库函数的包装,这有更简洁的语法。println就是其中之一。
  • 和很多现代语言一样,可以省略每行代码结尾的分号。

1.2 函数

1.2.1 函数类型

上面已经看了一个没有返回值得函数,下面我们看一个有返回值的函数:

fun max(a: Int, b: Int): Int { return if (a > b) a else b
}
println(max(1, 2)) //2

我们看到返回类型放在了参数列表之后。

注意:在Kotlin中if是个有返回值的表达式。类似于Java中的三目运算符(a > b)? a : b

函数声明以fun开始,函数名紧随其后,例子中函数名是max,接下来是参数列表,之后跟着返回类型,之间用冒号隔开。

无返回类型

fun 函数名(参数列表){函数体
}

有返回类型

fun 函数名(参数列表):返回类型{函数体
}

语句表达式

在Kotlin中,if是个表达式,而不是一个语句。语句和表达式的区别在于,表达式是一个值,可以被用作另外表达式的一部分;而语句总是一个包含它的代码块内的顶层元素,没有自己的值。在Java中,所有的控制结构都是语句,但是在Kotlin中,大部分控制结构,除了循环(for , do和do/while),是表达式。联合控制结构和其他的表达式,可以让你简洁表达许多通常的模式。

另外一方面,在Java中赋值是表达式,但是在Kotlin中变成了语句。这有效避免了比较和赋值之间的混淆,这个混淆也是错误的一个来源。

1.2.2 表达式函数体

可以让前面的函数变得更简单。因为他的函数体是由单个表达式构成,可以用这个表达式作为完整的函数体,并去掉花括号和return语句:

fun max(a: Int, b: Int): Int = if (a > b) a else b

如果用花括号来表达函数主体,我们叫这个函数为代码块体,如果直接返回表达式,我们叫它为表达式体

INTELLIJ IDEA提示 : IntelliJ IDEA提供了在两种不同函数风格“Convert to expression body”和 “Convert to block body”之间的转换

表达式体的函数在Kotlin代码中很常见,不光用在一些简单的函数中,也用在许多复杂的表达式中,如:if、when、try等,后续介绍

1.2.3 类型推导

我们的max函数还可以进一步简化,如下:

fun max(a: Int, b: Int) = if (a > b) a else b

为什么函数没有返回类型的声明呢?作为一个静态类型语言,Kotlin不是要求每个表达式都应该在编译期具有类型吗?事实上,每个变量和表达式都有返回类型。但是对于表达式体的函数,编译器可以分析作为函数体的表达式,用它的类型作为返回类型,即使没有显示的写出来。分析的这个类型通常叫类型推导(type inference)

注意:省略返回类型仅仅在表达式体的函数中允许。有代码块体的有返回值的函数,你必须指明返回类型和显示的返回语句。实际中的函数通常非常长,可能包含很多返回语句,有显示的返回类型和语句可以帮助你快速的知道什么被返回。

1.3 变量

在Java中,你用类型声明变量。但是在Kotlin中,许多变量的类型都可以省略,所以在Kotlin中以关键字开始,然后是变量名,最后加上类型(也可以不加)。
省略类型:

val question = "The Ultimate Question of Life, the Universe, and Everything"
val answer = 42

显示类型:

val answer: Int = 42

不可省略类型:
变量没有初始化器,需要显示的指出

val answer:Int
answer = 42

可变变量和不可变量

  • val(来源于value)— 不变的引用。一旦声明为val的量初始化后,不能够重新赋值。对应于Java里面的final变量
  • var(来源于variable)— 可变的引用。变量的值可以改变。对应于Java里面的正常的变量(非final)

通常,尽量声明所有的变量为val关键词。只有有需要的时候,才变为var。使用不可变引用、不可变对象及无无副作用的函数让你的代码更接近函数式编程风格

定义了val变量的代码块执行期间,val变量只能进行唯一一次初始化。但是,如果编译器能确保只有唯一一条初始化语句被执行,可以根据条件使用不同的值来初始化它:

val message: String
if (canPerformOperation()) {message = "Success"// ... perform the operation }
else {message = "Failed"
}

**注意:**尽管val引用自身是不可变得,但是它指向的的对象可能是可变的:

val languages = arrayListOf("Java") //声明不可变的引用
languages.add("Kotlin")//改变引用指向的实例

**注意:**尽管var关键词允许变量改变他的值,但是它的类型是确定的:

var answer = 42
answer = "no answer"//编译错误:类型不匹配

编译器只会根据初始化器来推断变量的类型,在决定类型的时候不会考虑后续的赋值操作。

如果你想在变量里面存储一个不匹配的类型的值,你必须转换或者协变这个值到正确的类型。

1.4 更容易的字符串格式化:字符串模板

fun main(args: Array<String>) { //打印“Hello,Kotlin”,如果输入参数为Bob,则打印“Hello,Bob”val name = if (args.size > 0) args[0] else "Kotlin" println("Hello, $name!")
}

这个例子引进了一个功能叫字符串模板(string templates)。和其他脚本语言一样,Kotlin允许在字符串字面量中,通过$字符放在变量名前面,引用本地变量。这个同Java中的字符串连接("Hello, " + name + “!”), 但是更加紧凑和有效率(注:都是创建StringBuilder,添加常量部分和变量值,Java虚拟机有优化)。

如果你引用一个不存在的本地变量,因为表达式会静态检查,这些代码会编译不成功。如果你想在字符串中包含$符号,用println("$x")换码,打印出$x,而不是把x翻译为一个变量的引用。

不限于一个简单的变量名,你也可以用更加复杂的表达式,仅仅只要在表达式括上花括号:

fun main(args: Array<String>) { //用${}插入args数组的第一个元素if (args.size > 0) { println("Hello, ${args[0]}!") }
}

你也可以双引号内陷双引号,只要他们是在同一个表达式:

fun main(args: Array<String>) { println("Hello, ${if (args.size > 0) args[0] else "someone"}!")
}

二、类和属性

面向对象编程可能不是什么新鲜话题,Kotlin这方面也似曾相识,但是你会发现许多常见的任务使用更少的代码就可以完成。

让我们看看一个简单的JavaBean的Person类,现在只包含一个name属性:

/* Java */
public class Person { private final String name;public Person(String name) { this.name = name;     }public String getName() { return name; }
}

在Java中,构造方法的方法体常常包含重复内容,把参数赋值给有着相同名称的字段。在Kotlin中,这个逻辑不需要如此多的样板代码。

/* Kotlin*/
class Person(val name: String)

这种类(只有数据没有其他代码)通常被叫做值对象

注意:从java到Kotlin的转换过程中public修饰符消失了。在Kotlin中public是默认的可见性。

2.1 属性

  • 在java中,如果你想让类的使用者访问到数据,需要提供访问方法:一个getter、可能有一个setter,setter可能包含一些额外的逻辑,验证传递值,或者发送值变化的通知等等。
  • 但是在Koltin中,属性是头等的语言特信,完全替代字段和访器方法。使用val和var关键字。声明val的属性只读,var是可变的
class Person( val name: String, //只读属性:自动生成一个域和简单的gettervar isMarried: Boolean //可写属性:一个域,getter和setter
)

接下来我们看下如何使用上面定义好的Person类:

val person = Person("Bob", true)
println(person.name)// Bob
println(person.isMarried) //true

现在可以直接引用属性,不再需要getter,逻辑没变,代码更加简洁。

小贴士:

  • 你可以在Java定义的类中使用Kotlin的属性语法。在Java类中的getter可以在Kotlin中val属性获取,getter/setter可以通过var属性获取。比如,如果在Java类定义了setName和setName的方法,那么可以通过叫name的属性获取。如果类定义了isMarried和setMarried方法,相应的Kotlin属性叫isMarried。

2.2 自定义属性访问器

这个部分,你将看到怎么自定义实现一个属性访问器。假设你声明了一个长方形,它可以告诉是不是一个正方形。你没必要用单独的域存储这个信息,因为你需要动态检查高是否等于宽:

class Rectangle(val height: Int, val width: Int) { val isSquare: Boolean get() { //Property getter declarationreturn height == width}
}

isSquere属性不需要一个域来存储它的值。它仅仅是自定义实现的getter。

val rectangle = Rectangle(41, 43)
println(rectangle.isSquare) //false

2.3 Kotlin源码布局:目录和包

Java把所有的类放进包里面。Kotlin也像Java,有包的概念。每个Kotlin文件在开头有package语句,文件中所有的声明(类、函数和属性)将放在这个包下。如果其他的文件在同一包下,里面所有的定义可以直接使用;如果这些定义在不同包里面,那么他们需要导入。就像在Java中,导入语句放置在文件的开头,使用import关键词。下面是个例子,展示包声明和导入语句:

package geometry.shapes //包声明import java.util.Random //导入标准Java库类class Rectangle(val height: Int, val width: Int) {val isSquare: Booleanget() = height == width
} fun createRandomRectangle(): Rectangle {val random = Random()return Rectangle(random.nextInt(), random.nextInt())
}

接下来看一下java和kotlin的目录结构


如上图:java中,目录层级结构照搬了包层级结构

如上图:kotlin中,不需要遵循目录层级结构

在kotlin中,可以把多个类放在同一个文件中,文件的名字还可以随意选择。

但是,在大多数情况下,跟随Java目录结构和根据包结构把源码组织成目录,是最佳实践。特别是Kotlin和Java混合的项目,坚持这样的结构特别重要。因为这样做可以让你逐步迁移代码,而没有引入意外的情况。
但是当类很小的时候(在Kotlin中,这些经常存在)。请你不要犹豫把多个类合成到同一个文件。

总结

  • fun关键字用来声明函数。val关键字和var关键字分别用来声明只读变量和可变变量
  • 字符串模板帮助你避免繁琐的字符串拼接。在字符串前加上或者或者或者{}包围一个表达式,来把值注入到字符串中。
  • 实体类(值对象类)在Kotlin中以更简单的方式表示。
  • 在kotlin中,可以把多个类放在同一个文件中,文件的名字还可以随意选择。

扫码关注公众号“伟大程序猿的诞生“,更多干货新鲜文章等着你~

公众号回复“资料获取”,获取更多干货哦~

有问题添加本人微信号“fenghuokeji996” 或扫描博客导航栏本人二维码

Kotlin实战【二】Kotlin基本要素相关推荐

  1. Kotlin实战指南二十:flow

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/117370700 本文出自[赵彦军的博客] 文章目录 往期精彩文章 flow 是啥 ...

  2. Kotlin实战(三)

    一.元组 1.1.二元元组 data class Pair<out A, out B>(public val first: A,public val second: B ) : Seria ...

  3. Kotlin实战指南十九:use 函数魔法

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/117366756 本文出自[赵彦军的博客] 文章目录 往期精彩文章 use函数 往期 ...

  4. Kotlin实战指南十八:open、internal 关键字使用

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/117365712 本文出自[赵彦军的博客] 文章目录 往期精彩文章 open关键字 ...

  5. Kotlin实战指南十七:JvmField、JvmStatic使用

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/116668666 本文出自[赵彦军的博客] 文章目录 往期精彩文章 @JvmFiel ...

  6. Kotlin 实战翻译 —— 仿微信图片选择开源库ImagePicker

    2017.10.27补充 在用Kotlin写项目的时候由于不能使用生成成员变量的快捷键,导致我写findViewById浪费了好多时间,后来才发现Kotlin对Android有更好的支持,可以完全不用 ...

  7. Kotlin实战练习——自定义圆形图片三种实现方式

    Kotlin实战练习--自定义圆形图片三种实现方式 前言 如今Kotlin越来越重要,本人也开始了Kotlin的学习.为了检测学习效果,加深学习印象,同时回顾一下以前的一些知识点,决定从写一个自定义圆 ...

  8. Android kotlin实战之协程suspend详解与使用

    前言 Kotlin 是一门仅在标准库中提供最基本底层 API 以便各种其他库能够利用协程的语言.与许多其他具有类似功能的语言不同,async 与 await 在 Kotlin 中并不是关键字,甚至都不 ...

  9. 深入理解 Kotlin coroutine (二)

    原文链接:https://github.com/enbandari/Kotlin-Tutorials 上周我们把 Kotlin Coroutine 的基本 API 挨个讲了一下,也给出了一些简单的封装 ...

  10. Kotlin实战指南七:单例模式

    转载请标明出处:https://blog.csdn.net/zhaoyanjun6/article/details/87941461 本文出自[赵彦军的博客] 单例模式 无参单例模式-线程安全 懒加载 ...

最新文章

  1. 智课雅思词汇---五、优词词根字典
  2. CCS代码编辑的几个常用设置
  3. 单位四元数(unit quaternion)
  4. mysql支持asp.net_关于Mysql + asp.net注射能支持多语句的感慨(2月)
  5. 史上最详尽的NLP预处理模型汇总
  6. GitPush时提示:fatal: The remote end hung up unexpectedly
  7. 仿微信公众号后台管理-自定义菜单
  8. json_encode 处理中文乱码
  9. 【Linux学习篇】This virtual machine is configured for 64-bit guest operating systems.……
  10. 图灵奖得主Bengio:深度学习让AI得以推理和想象,不会被取代
  11. 多个命令执行结果输出到同一个文件(批处理)
  12. 太扎心!10亿网民:4成初中学历,月收入超5000元不足3成
  13. ZOJ 4028 15th浙江省省赛E. LIS(神奇贪心)
  14. html立体音乐相册源码,印记工坊立体音乐相册 v 1.8 官方版|印记工坊立体音乐相册官方版|印记工坊立体音乐相册电脑版_最火软件站...
  15. vue word 转换html渲染页面(mammoth)
  16. python简单实现爬取小说《天龙八部》,并在页面本地访问
  17. everedit选择_EverEdit
  18. python监听多个udp端口_尝试实现非阻塞python-udp多端口获取wierd异常
  19. 短视频优质作者必备|配音神器分享|那些你刷视频时肯定听过的声音
  20. Collections详解

热门文章

  1. Javascript特效:电商商品展示放大镜
  2. C#:$符号和@符号的用法介绍
  3. mysql 周 获取日期_MySQL获取日期周、月、天,生成序号
  4. 自动驾驶_产品象限图_清洁机器人场景
  5. 目标检测(8):CenterNet-Objects as Points-将目标建模为边界框中心点的方法
  6. ACM ICMR 2021雷达目标检测挑战赛(ROD2021)
  7. 推荐Android中两个很好用的banner,可无限轮播,可使用第三方图片加载框架加载网络图...
  8. python 与 json
  9. POJ 1002 电话号码字符串处理
  10. 用C语言进行BMP文件的读写