文章目录
准备工作
1.下载android studio 随意创建一个项目.
2.创建一个module.
3.创建一个kotlin文件并手写main方法.
4.点击运行.
变量
//val 只可赋值一次
val a:Int = 1 //立即赋值
val b = 1 //'int'类型推断
val c :Int // 不提供初始值
c = 1 //延迟赋值
//var 只重新赋值
var d = 1
//a = 2(报错)
d = 2
基本类型
//数字
val oneByte:Byte = 1 //Byte 8位
val oneShort:Short = 1 //Short 16位
val one:Int = 1 //Int 32位
val oneLong:Long = 1L//Long 64位
// 浮点
val oneFloat:Float = 1.0F //Float 大小32位 有效位 24
val oneDouble:Double = 1.0 //Double 大小64位 有效位 53
kotlin在jvm上对Integer的内存优化在-128-127之间.
val a:Int = 130
val boxedA:Int? = a
val anotherBoxedA:Int? = a
println(boxedA == anotherBoxedA)//true
println(boxedA === anotherBoxedA)//false
运算符 + - * / %
浮点数比较
- 平等检查:a==b a != b
- 比较运算符: a < b ,a > b ,a <= b, a >= b
- 范围实例化和范围检查 :a…b , x in a…b, x !in a…b
//布尔值
var myTrue:Boolean = true
var myfalse:Boolean = false
println(myTrue || myfalse)//true
println(myTrue && myfalse)//false
println(!myTrue)//false
//字符Char
val aChar:Char = 'a'
//字符串String
val str = "abf 123"
//数组
val x: IntArray = intArrayOf(1, 2, 3)
//输出 1 2 3
val arr = IntArray(5)
//输出 0 0 0 0 0
val arr = IntArray(5) { 1 }
//输出 1 1 1 1 1
var arr = IntArray(5) { it * 1 }
//输出 0 1 2 3 4
类型检查 is !is
强制转换 as
函数
fun firstFun(){
println("第一个fun")
}
//带返回值
fun firstFun():Int{
return 1
}
//输出1
fun sum() = "函数表达式"
类
//定义一个类
class first
//加构造参数
class first(var a:Int,var b:Int){
fun sum() = a + b
}
//两个构造参数
class first(var a:Int,var b:Int){
constructor( a:Int, b:Int, c:Int):this(a,b){
}
}
class first(var a:Int,var b:Int){
fun sum() = a + b
}
//构造参数添加默认值
class first(var a:Int = 1,var b:Int = 2){
fun sum() = a + b
}
//初始化顺序
class InitOrderDemo(name: String) {
val firstProperty = "1: $name".also(::println)
init {
println("2: $name")
}
val secondProperty = "3: ${name.length}".also(::println)
init {
println("4: ${name.length}")
}
}
//init执行在constructor前
class Constructors {
constructor(i: Int) {
println("2 Constructor $i")
}
init {
println("1")
}
}
继承
//继承.要使类可继承,需要用open修饰.
open class first
class two(var a:Int,var b:Int):first()
//执行顺序
open class Base(val name: String) {
init { println("2 Initializing a base class") }
open val size: Int =
name.length.also { println("3 Initializing size in the base class: $it") }
}
class Derived(
name: String,
val lastName: String,
) : Base(name.replaceFirstChar { it.uppercase() }.also { println("1 Argument for the base class: $it") }) {
init { println("4 Initializing a derived class") }
override val size: Int =
(super.size + lastName.length).also { println("5 Initializing size in the derived class: $it") }
}
// 内部类
//在内部类中,使用super外部类名限定的关键字来访问外部类的超类super@Outer
open class Rectangle {
open fun draw() { println("Drawing a rectangle") }
val borderColor: String get() = "black"
}
class FilledRectangle: Rectangle() {
override fun draw() {
val filler = Filler()
filler.drawAndFill()
}
inner class Filler {
fun fill() { println("Filling") }
fun drawAndFill() {
super@FilledRectangle.draw() // 调用Rectangle 的 draw()
fill()
println("color ${super@FilledRectangle.borderColor}") // 调用Rectangle 的 borderColor 的 get()
}
}
}
fun main() {
val fr = FilledRectangle()
fr.draw()
}
//输出
//Drawing a rectangle
//Filling
//color black
Overriding rules
当父类与实现接口方法名耦合时。分别调用父类和接口的方法。
open class Rectangle {
open fun draw() { }
}
interface Polygon {
fun draw() { } // interface members are 'open' by default
}
class Square() : Rectangle(), Polygon {
override fun draw() {
super<Rectangle>.draw() // 调用 Rectangle.draw()
super<Polygon>.draw() // 调用 Polygon.draw()
}
}
接口 interface
//使用关键字定义接口interface:
interface MyInterface {
fun bar()
fun foo() {
}
}
一个类或对象可以实现一个或多个接口
class Child : MyInterface {
override fun bar() {
// body
}
}
接口属性
interface 属性实现get方法后,实现接口的类颗不用重写此属性。
interface MyInterface {
val prop: Int // abstract
val propertyWithImplementation: String
get() = "foo"
fun foo() {
print(prop)
}
}
class Child : MyInterface {
override val prop: Int = 29
}
接口继承
interface Named {
val name: String
}
interface Person : Named {
val firstName: String
val lastName: String
override val name: String get() = "$firstName $lastName"
}
data class Employee(
// 不用实现name
override val firstName: String,
override val lastName: String,
val position: Position
) : Person
函数(SAM)接口
只有一个抽象方法的接口称为功能接口或单一抽象方法 (SAM) 接口。功能接口可以有多个非抽象成员,但只有一个抽象成员。
fun interface KRunnable {
fun invoke()
}
val isEven = IntPredicate { it % 2 == 0 }
fun main() {
println("Is 7 even? - ${isEven.accept(7)}")
}
函数类型的类型别名
typealias IntPredicate = (i: Int) -> Boolean
val isEven: IntPredicate = { it % 2 == 0 }
fun main() {
println("Is 7 even? - ${isEven(7)}")
}
功能接口和类型别名有不同的用途。类型别名只是现有类型的名称——它们不会创建新类型,而函数式接口会。您可以提供特定于特定功能接口的扩展,使其不适用于普通函数或其类型别名。
类型别名只能有一个成员,而功能接口可以有多个非抽象成员和一个抽象成员。功能接口也可以实现和扩展其他接口。
可见性修饰符
Kotlin 中有四个可见性修饰符:private、protected、internal和public. 默认可见性是public。
- 如果您不使用可见性修饰符,public则默认使用,这意味着您的声明将在任何地方可见。
- 如果将声明标记为private,它将仅在包含该声明的文件中可见。
- 如果将其标记为internal,它将在同一模块中的任何地方可见。
open class Outer {
private val a = 1
protected open val b = 2
internal open val c = 3
val d = 4
protected class Nested {
public val e: Int = 5
}
}
class Subclass : Outer() {
override val b = 5 // 'b' is protected
override val c = 7 // 'c' is internal
}
class Unrelated(var o: Outer) {
fun avv(){
o.c // 'c' is internal
}
}
Modules
internal可见性修饰符意味着该成员在同一模块中是可见的。更具体地说,模块是一组编译在一起的 Kotlin 文件,例如
- 一个 IntelliJ IDEA 模块。
- 一个 Maven 项目。
- Gradle 源集(test源集可以访问 的内部声明main除外)。
- 使用Ant 任务的一次调用编译的一组文件。
函数扩展
//在不使用继承的情况下给Fdd添加一个add方法
class Fdd{
}
fun Fdd.add(){
}
可以在另一个类中声明一个类的扩展。
class Host(val hostname: String) {
fun printHostname() { print(hostname) }
}
class Connection(val host: Host, val port: Int) {
fun printPort() { print(port) }
fun Host.printConnectionString() {
printHostname() // calls Host.printHostname()
print(":")
printPort() // calls Connection.printPort()
}
fun connect() {
/*...*/
host.printConnectionString() // calls the extension function
}
}
如果调度接收器和扩展接收器的成员之间发生名称冲突,则扩展接收器优先。要引用调度接收者的成员,您可以使用限定this语法。
属性扩展
val Fdd.a :Int
get() = 1
伴生对象扩展
class MyClass {
companion object { } // will be called "Companion"
}
fun MyClass.Companion.printCompanion() { println("companion") }
数据类
data class User(val name: String, val age: Int)
编译器自动从主构造函数中声明的所有属性派生以下成员:
- equals()/hashCode()
- toString()输出"User(name=John, age=42)"
- componentN()与声明顺序中的属性相对应的函数。
- copy()
数据类和解构声明
val jane = User("Jane")
val (name) = jane
密封类
以sealed修饰的类或者接口
sealed interface Error
sealed class IOError(): Error //仅在相同的包和模块中扩展
open class CustomError(): Error //可以扩展到任何地方
嵌套类和内部类
class Outer {
private val bar: Int = 1
class Nested {
fun foo() = 2
}
}
val demo = Outer.Nested().foo() // == 2
内部类
标记为的嵌套类inner可以访问其外部类的成员。内部类携带对外部类对象的引用:
class Outer {
private val bar: Int = 1
inner class Inner {
fun foo() = bar
}
}
val demo = Outer().Inner().foo() // == 1
枚举类
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
由于每个枚举都是枚举类的一个实例,因此可以将其初始化为:
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF)
}
内联类
有时,业务逻辑需要围绕某种类型创建包装器。但是,由于额外的堆分配,它会引入运行时开销。此外,如果包装类型是原始类型,则性能损失很糟糕,因为原始类型通常由运行时进行大量优化,而它们的包装器没有得到任何特殊处理。
为了解决这些问题,Kotlin 引入了一种特殊的类,称为内联类。内联类是基于值的类的子集。他们没有身份,只能持有价值观。
要声明内联类,请value在类名前使用修饰符:
value class Password(private val s: String)
// For JVM backends
@JvmInline
value class Password(private val s: String)
@JvmInline
value class UInt(val x: Int)
// 在jvm上表示 'public final void compute(int x)'
fun compute(x: Int) { }
// 在jvm上表示 'public final void compute(int x)'
fun compute(x: UInt) { }
条件表达式
fun maxOf(a: Int,b:Int):Int{
if (a > b){
return a
}else{
return b
}
}
//或者
fun maxOf(a: Int,b:Int) = if (a > b) a else b
//when表达式
fun describe(obj:Any):String=
when(obj){
1 -> "one"
"hellow" -> "Greeting"
is Long -> "是 Long"
!is String ->"不是String"
else -> ""
}
val items = listOf<Int>(1,2,3,4,5)
when{
1 in items -> println("items中有1")
6 in items -> println("items中有6")
}
//输出items中有1
对象表达式
val helloWorld = object {
val hello = "Hello"
val world = "World"
override fun toString() = "$hello $world"
}
从object 继承匿名对象
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { /*...*/ }
override fun mouseEntered(e: MouseEvent) { /*...*/ }
})
如果超类型具有构造函数,则将适当的构造函数参数传递给它。多个超类型可以指定为冒号后的逗号分隔列表:
open class A(x: Int) {
public open val y: Int = x
}
interface B { /*...*/ }
val ab: A = object : A(1), B {
override val y = 15
}
伴随对象
类中的对象声明可以用companion关键字标记:
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
可以通过使用类名作为限定符简单地调用伴生对象的成员:
val instance = MyClass.create()
伴生对象的名称可以省略,在这种情况下Companion将使用名称:
class MyClass {
companion object { }
}
val x = MyClass.Companion
类成员可以访问相应伴随对象的私有成员。
委托模式
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main() {
val b = BaseImpl(10)
Derived(b).print()
}
委托属性
- Lazy properties:该值仅在首次访问时计算。
- Observable properties:通知侦听器有关此属性的更改。
- 将属性存储在Map中,而不是每个属性的单独字段。
class Example {
var p: String by Delegate()
}
属性委托不必实现接口,但必须提供getValue()函数(和setValue()for vars)。
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name}' in $thisRef.")
}
}
当您读取p委托给 的实例的from 时Delegate,将调用getValue()函数 from Delegate。它的第一个参数是您从中读取的对象p,第二个参数包含对p自身的描述(例如,您可以取其名称)。
val e = Example()
println(e.p)
打印结果:Example@33a17727, thank you for delegating ‘p’ to me!
e.p = "NEW"
当您分配给 时p,将调用该setValue()函数。前两个参数是相同的,第三个保存被赋值的值:
打印结果 :NEW has been assigned to 'p' in Example@33a17727.
lazy
lazy()是一个接受 lambda 并返回 的实例的函数,该实例Lazy可以作为实现惰性属性的委托。第一次调用get()执行传递给的 lambdalazy()并记住结果。后续调用get()简单地返回记住的结果。
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
fun main() {
println(lazyValue)
println(lazyValue)
}
输出:computed!
Hello
Hello
可观察的属性
Delegates.observable()接受两个参数:初始值和修改处理程序。
每次分配给属性时都会调用处理程序(在执行分配之后)。它具有三个参数:分配给的属性、旧值和新值
class User {
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println("$old -> $new")
}
}
fun main() {
val user = User()
user.name = "first"
user.name = "second"
}
输出
<no name> -> first
first -> second
委托属性
在不删除或者更改老属性的情况下,创建一个新属性,新属性值更改,老属性随着更改。老属性更改,新属性不变。
class MyClass {
var newName: Int = 0
@Deprecated("Use 'newName' instead", ReplaceWith("newName"))
var oldName: Int by this::newName
}
fun main() {
val myClass = MyClass()
myClass.oldName = 42
println(myClass.newName) // 42
}
在map中存储属性
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
val user = User(mapOf(
"name" to "John Doe",
"age" to 25
))
println(user.name) // "John Doe"
println(user.age) // 25
对于只读属性 ( val),委托应提供具有getValue()以下参数的运算符函数:
- thisRef必须与属性所有者的类型相同或超类型(对于扩展属性,它应该是被扩展的类型)。
- property必须是类型KProperty<*>或其超类型。
getValue()必须返回与属性(或其子类型)相同的类型。
class Resource
class Owner {
val valResource: Resource by ResourceDelegate()
}
class ResourceDelegate {
operator fun getValue(thisRef: Owner, property: KProperty<*>): Resource {
return Resource()
}
}
对于可变属性 ( var),委托必须另外提供具有setValue()以下参数的运算符函数:
- thisRef必须与属性所有者的类型相同或超类型(对于扩展属性,它应该是被扩展的类型)。
- property必须是类型KProperty<*>或其超类型。
- value必须与属性(或其超类型)具有相同的类型。
class Resource
class Owner {
var varResource: Resource by ResourceDelegate()
}
class ResourceDelegate(private var resource: Resource = Resource()) {
operator fun getValue(thisRef: Owner, property: KProperty<*>): Resource {
return resource
}
operator fun setValue(thisRef: Owner, property: KProperty<*>, value: Any?) {
if (value is Resource) {
resource = value
}
}
}
类型别名
类型别名为现有类型提供替代名称。如果类型名称太长,您可以引入不同的较短名称并使用新名称。
缩短长泛型
typealias NodeSet = Set<Network.Node>
typealias FileTable<K> = MutableMap<K, MutableList<File>>
为函数类型提供不同的别名
typealias MyHandler = (Int, String, Any) -> Unit
typealias Predicate<T> = (T) -> Boolean
为内部类和嵌套类指定新名称:
class A {
inner class Inner
}
class B {
inner class Inner
}
typealias AInner = A.Inner
typealias BInner = B.Inner
typealias Predicate<T> = (T) -> Boolean
fun foo(p: Predicate<Int>) = p(42)
fun main() {
val f: (Int) -> Boolean = { it > 0 }
println(foo(f)) // prints "true"
val p: Predicate<Int> = { it > 0 }
println(listOf(1, -2).filter(p)) // prints "[1]"
}
for while 循环
循环遍历
val items = listOf<Int>(1,2,3,4,5)
for (item in items){
println(item)
}
for (index in items.indices){
println(items[index])
}
items.forEach {
println(it)
}
var index = 0
while (index < items.size){
println(items[index])
}
循环跳出jumps与返回Returns
Kotlin 有三种结构跳转表达式:
- return默认情况下从最近的封闭函数或匿名函数返回。
- break终止最近的封闭循环。
- continue进入最近的封闭循环的下一步。
first@ for (i in 1..100) {
if (i == 10) break@first
for (j in 1..100) {
print("j=$j")
if (j == 5) break@first
}
}
// continue使用方式与break一样
//中断forEach
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
if (it == 3) return@lit
print(it)
}
}
//外部嵌套run函数
run loop@{
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@loop
print(it)
}
}