类与对象

1. 属性与字段

  • Getters与Setters

set方法与get方法中如果需要用到变量,需要用field来表示当前变量而不能直接引用,否则会造成死循环。

关键字field表示幕后字段,只能在gettersetter内对它访问。

// 正确方法
var gender: String = "Man"set(value) {println("setter $value")field = value}// 错误方法
var gender: String = "Man"set(value) {println("setter $value")gender = value}

2. 可见性修饰符

private:不指定任何可见行修饰符,默认为public

protected:只在声明他的文件内可见

internal:在相同模块内随处可见

public:不适用与顶层声明

注:要使用另一包中可见的顶层声明,仍需要将其导入进来。

  • 类和接口

private:只在该类的内部(包括所有成员)可见

protected:类内部与子类中可见

internal:能见到类声明的本模块内的任何客户端都可见

public:能见到类声明的任何客户端

注:覆盖一个protected成员并没有显式指定可见性,该成员仍为protected

  • 构造函数

构造函数默认都是public

// 指定一个类的主构造函数的可见性,需要添加显式constructor关键字
class C private constructor(a: Int) {  }

3. 扩展

  • 扩展函数

扩展函数是静态分发的,它们是由扩展函数所在的表达式的类型来决定的,而不是由表达式运行时求值结果决定的。

fun main() {open class Shapeclass Rectangle: Shape()fun Shape.getName() = "Shape"fun Rectangle.getName() = "Rectangle"fun printClassName(s: Shape) {println(s.getName())}    printClassName(Rectangle())
}// 输出:Shape

如果一个类的成员函数与扩展函数具有相同的接收者类型和形同的函数名,并且都适用该定的参数,这种情况总是取成员函数。

fun main() {class Example {fun printFunctionType() { println("Class method") }}fun Example.printFunctionType() { println("Extension function") }Example().printFunctionType()
}// 输出:Class Method
  • 拓展声明为成员

声明为成员的扩展可以声明为open并在子类中覆盖。这意味着这些函数的分发对于分发接收者类型是虚拟的,但对于扩展接收者类型是静态的。

4. 数据类

主构造函数需要至少有一个参数。

componentN()函数按声明顺序对应与所有属性。

5. 密封类

声明:类名前添加sealed修饰符。

一个密封类是自身的抽象的,它不能直接实例化。

密封类用来表示受限的类继承结构:当一个值为有限几种类型,而不能有其他类型时。

使用密封类的关键好处:使用when表达式的时候,如果能够验证语句覆盖了所有情况,就不需要为该语句再添加else子句了。

sealed class SealedClassclass Bird(var name: String) : SealedClass()
class Fish(var name: String) : SealedClass()fun getAnimalName (animal: SealedClass): String = when(animal) {is Bird -> "鸟类:${animal.name}"is Fish -> "鱼类:${animal.name}"
}

6. 泛型

泛型协变:取出对象(out)是安全的,传入对象(in)不可靠。

泛型逆变:传入对象(in)是安全的,取出对象(out)不可靠。

  • 声明处型变(declaration-site variance)

注:只能读取的对象为生产者(out),只能写入的对象为消费者(in)

标注Source的类型参数T来确保它从Source<T>中返回(生产),并从不被消费。使用out修饰符。

class User<out T> {val info: Tconstructor(info: T) {this.info = info}fun test(): T {println("执行test方法")return info}
}

当一个类 C 的类型参数 T 被声明为 out时,它就只能出现在 C 的成员的输出位置,但回报是 C<Base> 可以安全地作为 C<Derived>的超类。out修饰符被称为型变注解,也称为声明处型变

in使得一个类型参逆变:只能被消费而不能被生产。

如果泛型T只出现在该类的方法的返回值声明中,那么该类泛型形参即可使用out修饰T;如果泛型T只出现在该类的方法的形参声明中,那么该泛型形参即可使用in修饰T

  • 类型投影(使用处型变,type projections)
import java.lang.StringBuilderfun main() {fun fill(dest: Array<in String>, value: String) {if (dest.isNotEmpty()) {dest[0] = value}}val arr1: Array<CharSequence> = arrayOf("a", "b", StringBuilder("cc"))fill(arr1, "kotlin")println(arr1.contentToString())var intArr: Array<in Int> = arrayOf(1, 2, 3)intArr[0] = 4println(intArr.contentToString())val numArr: Array<Number> = arrayOf(1, 2.1, 3.33333)intArr = numArrprintln(intArr.contentToString())}

Array<out Any>相当于Java的泛型上限:Array<? extends Objcject>

Array<in Int>相当于Java的泛型下限:Array<? super Int>,因此这种泛型型变用于支持逆变,还可以保证向其中安全地添加元素。

  • 星投影

类似Java的原始数据类型。

如果类型被声明为Interface Function<in T, out U>,则:

Function<*, String>表示Function<in Nothing, String>

Function<Int, *>表示Function<Int, out Any?>

Function<*, *>表示Function<in Nothing, out Ant?>

  • 泛型函数

类型参数放在函数名称之前。

fun <T> singletonList(item: T): List<T> {  }// 调用
val a1 = singletonList<Int>(1)
val a2 = singletonList(1)
  • 泛型约束

上界:冒号之后指定的类型是上界。

fun <T : Comparable<T>> sort(list: List<T>) {  }

默认的上界是Any?。尖括号中只能指定一个上界,如果同一类型参数需要多个上界,则需要一个单独的where子句。

fun <T> copyWhenGreater(list: List<T>, threshold: T): List<String>where T : CharSequence,T : Comparable<T> {return list.filter { it > threshold }.map { it.toString() }
}

7. 嵌套类与内部类

  • 嵌套类
class Outer {private val bar: Int = 1class Nested {fun foo() = 2val innerBar = bar  // 编译无法通过}
}val demo = Outer.Nested().foo()  // ==2
  • 内部类

inner关键字的嵌套类能够访问外部类的成员。内部类带有一个对外部类对象的引用。

class Outer {private val bar: Int = 1inner class Inner {fun foo() = bar}
}val demo = Outer().Inner().foo() // == 1
  • 匿名内部类

使用对象表达式创建匿名内部类实例。

window.addMouseListener(object : MouseAdapter() {override fun mouseClicked(e: MouseEvent) {  }override fun mouseEntered(e: MouseEvent) {  }
})

8. 对象

  • 对象表达式

如果只需要一个对象,采用如下方式:

fun foo() {val adHoc = object {var x: Int = 0var y: Int = 0}print(adHoc.x + adHoc.y)
}
  • 伴生对象

类内部的对象声明可以用companion关键字标记。

class MyClass {companion object Factory {fun create(): MyClass = MyClass()}
}

伴生对象的成员可通过只使用类名作为限定符来调用。

val instance = MyClass.create()

省略对象的名称将默认使用名称Companion

class MyClass {companion object { }
}val x = MyClass.Companion

其自身的类名可用作该类的伴生对象的引用。

class MyClass1 {companion object Named { }
}val x = MyClass1  // MyClass1$Named@816f27dclass MyClass2 {companion object { }
}val y = MyClass2  // MyClass2$Companion@87aac27

9. 类型别名

为现有类型提供替代名称。

class A {inner class Inner {fun inner() {println("A's inner")}}
}typealias AInner = A.Innerfun main() {val aInner: AInner = A().Inner()aInner.inner()  // A's inner
}

10. 内联类

内联类必须含有唯一的一个属性在主构造函数中初始化。

内联类支持普通类中的一些功能。特别是,内联类可以声明属性与函数。

inline class Name(val s: String) {val length: Intget() = s.lengthfun greet() {println("Hello, $s")}
}

注:内联类不能含有init代码块,不能含有幕后字段。

内联类只能含有简单的计算属性。

内联类允许继承接口,不能继承其他类。

interface Printable {fun prettyPrint(): String
}inline class Name(val s: String) : Printable {override fun prettyPrint(): String = "Let's $s!"
}
  • 表示方式

只要将内联类用作另一种类型,它就会被装箱。

interface Iinline class Foo(val i: Int) : I
class Bar(val i: Int): Ifun <T> id(x: T): T = xfun main() {val f = Foo(10)val foo = id(f)  // Foo(i=10)val b = Bar(20)val bar = id(b)  // Bar@1218025c
}
  • 内联类与类型别名

区别:类型别名与其基础类型是赋值兼容的,内联类不满足。内联类引入了一个真实的新类型。

typealias StringAlias = String
inline class StringInlineClass(val s: String)fun acceptString(s: String) {}
fun acceptStringAlias(n: StringAlias) {}
fun acceptStringInlineClass(p: StringInlineClass) {}fun main() {val stringAlias: StringAlias = ""val stringInlineClass: StringInlineClass = StringInlineClass("")val string = ""acceptString(stringAlias) // 正确: 传递别名类型的实参替代函数中基础类型的形参acceptString(stringInlineClass) // 错误: 不能传递内联类的实参替代函数中基础类型的形参acceptStringAlias(string) // 正确: 传递基础类型的实参替代函数中别名类型的形参acceptStringInlineClass(string) // 错误: 不能传递基础类型的实参替代函数中内联类类型的形参
}

11. 委托与委托属性

  • 标准委托

(1)延迟属性 Lazy

by lazy只能作用于val关键字标注的属性。当属性用到的时候才初始化lazy{}中的内容,再次调用属性的时候只会得到结果,不再执行lazy{}的运行过程。

val lazyValue: String by lazy {println("computed")"hello"
}fun main() {println(lazyValue)println(lazyValue)
}// 输出
// computed
// hello
// hello

(2)可观察属性 Observable

import kotlin.properties.Delegatesclass User {var name: String by Delegates.observable("<no name>") {prop, old, new ->println("$old -> $new")}
}fun main() {val user = User()user.name = "first"  // no name -> firstuser.name = "second" // first -> second
}

Delegates.observable接受两个参数:初始值与修改时处理程序(handler)。每次给属性赋值会执行该处理程序。它有三个参数:被赋值的属性、旧值与新值。

  • 将属性储存在映射映射中

这种情况下,可以使用映射实例自身作为委托来实现委托属性。

class User(val map: Map<String, Any?>) {val name: String by mapval age: Int by map
}fun main() {val user = User(mapOf("name" to "John","age"  to 25))println(user.name) // Johnprintln(user.age)  // 25
}
  • 属性委托要求

(1)val属性,必须提供getValue()函数,该函数具有如下参数:

thisRef与属性所有者类型(扩展属性的被扩展类型)相同或者是其超类型。

property必须是类型KProperty<*>或其超类型。

getValue()必须返回与属性相同的类型或其子类型。

(2)var属性,必须额外提供一个setValue()函数,该函数具有如下参数:

thisRef与属性所有者类型(扩展属性的被扩展类型)相同或者是其超类型。

property必须是类型KProperty<*>或其超类型。

value必须与属性类型相同或者是其超类型。

Kotlin学习笔记(一) 类与对象相关推荐

  1. Kotlin学习笔记-3 --- 类与对象

    文章参考 class KotlinClass {} /*** 空类 */ class EmptyClass 类的修饰符 1)classModifier: 类属性修饰符,标示类本身特性 abstract ...

  2. Python学习笔记 (类与对象)

    Python学习笔记 (类与对象) 1.类与对象 面向对象编程语言类: 一个模板, (人类)-是一个抽象的, 没有实体的对象: (eg: 张三, 李四) 属性: (表示这类东西的特征, 眼睛, 嘴巴, ...

  3. 冰冰学习笔记:类与对象(上)

    欢迎各位大佬光临本文章!!! 还请各位大佬提出宝贵的意见,如发现文章错误请联系冰冰,冰冰一定会虚心接受,及时改正. 本系列文章为冰冰学习编程的学习笔记,如果对您也有帮助,还请各位大佬.帅哥.美女点点支 ...

  4. 冰冰学习笔记:类与对象(下)

    欢迎各位大佬光临本文章!!! 还请各位大佬提出宝贵的意见,如发现文章错误请联系冰冰,冰冰一定会虚心接受,及时改正. 本系列文章为冰冰学习编程的学习笔记,如果对您也有帮助,还请各位大佬.帅哥.美女点点支 ...

  5. Java学习笔记_类和对象

    ·类:是一组相关属性和行为的集合,可以看成是一类事务的模板,使用事物的属性特征和行为特征来描述该类事物. ·属性:该事物的状态信息 ·行为:就是该事物能够做什么 ·对象:一类事物的具体体现,对象是类的 ...

  6. unity让对象作为参数_C#+Unity学习笔记:类与对象

    参考文献 蜜酒厅通讯社 游戏部 石中居士 对象(object):有状态.行为和身份的东西. 状态(state):表示物体特征的信息,可以用来跟踪对象的状态. 属性(properties):因为编程人员 ...

  7. Java学习笔记1——类和对象

    面向对象 对象:万物皆对象 面向对象 类:模子,属性+方法,类是对象的类型,是具有相同属性和方法的一组对象的集合 对象属性:对象拥有的各种特征,"对象有什么" 对象方法:对象执行的 ...

  8. Head First Java学习笔记(2):类与对象

    类 1.类是定义同一类所有对象的变量和方法的蓝图或原型. 2.实例变量的值由类的每个实例提供.当创建类的实例时,就创建了这种类型的一个对象,然后系统为类定义的实例变量分配内存.然后可以调用对象的实例方 ...

  9. java 由接口构造对象_Java学习笔记04——类和对象|抽象和接口|构造方法与继承...

    六.Java类 1.  Java中用关键字class来创建类. 2.  类中属性和方法称为类的成员;类的声明和方法要在同一个文件内,不同于C++. 3.  类的定义: [] class [extend ...

  10. C_PlusPlus学习笔记 - 3_类与对象 (C++语言程序设计【第三版】 郑莉等,清华大学出版社)

    3--类与对象 在我们熟悉的现实世界中,一切事物都是 对象 .对象可以是有形的,也可以是无形的. 对象可以是一个个体,也可以是由诸多其他对象组成. C++支持这种抽象,将抽象后的数据和函数封装在一起, ...

最新文章

  1. 模拟退火算法求解旅行商问题(python实现)
  2. 题目: javaweb前端素材管理系统(附免费下载源码链接)
  3. 一篇文章彻底明白Hive数据存储的各种模式
  4. 复杂度O(n)倒转链表
  5. 移动硬盘备份linux系统盘,将Ubuntu Linux系统放到你的移动硬盘
  6. 索引法则--最佳左前缀法则
  7. myelicpse无法连接mysql_myeclipse连接不到mysql
  8. 05Oracle P6培训系列:05创建项目
  9. tomcat7 安装和环境变量配置
  10. GH4199变形合金
  11. linux bigendian未定义,big endian与little endian
  12. Charles安装证书
  13. 输入两个正整数m和n,求出[m,n]区间的所有素数。
  14. 如何提供一个短链(URL shorter)生成服务
  15. 开源软件新时代 55个经典开源Windows工具
  16. 利用Calendar简洁制作万年历
  17. 博途SCL边沿触发(上升沿/下降沿)有输入无输出
  18. 企业服务总线--MuleESB简介
  19. 达梦DM数据库网页数据维护工具
  20. Docker 安装 TensorFlow GPU 实战 1

热门文章

  1. termux实现自动刷QQ福气袋
  2. goland中编辑tpl文件不高亮没智能补全的问题
  3. Android 框架练成 教你打造高效的图片加载框架
  4. 铁乐学python_day13_迭代器生成器
  5. Android5g手机,今年唯一小屏安卓5G手机!5.7寸+骁龙765G:真机亮相!
  6. 页面导成Word时实现横向打印
  7. 鸿蒙测试没有mate40,华为Mate40系列屏幕镜头爆料,没有鸿蒙2.0依旧会真香
  8. 惠普EliteBook-830-G5电脑 Hackintosh 黑苹果efi引导文件
  9. 《朋友还是对手》书中的精髓:奥地利学派和芝加哥学派两派共识远多于分歧,两派首先是朋友,其次才是对手。
  10. 传世服务器维护,win10系统玩传奇世界显示连接服务器失败的恢复技巧