Kotlin 用对象表达式和对象声明来实现创建一个对某个类做了轻微改动的类的对象,且不需要去声明一个新的子类。


对象表达式

通过对象表达式实现一个匿名内部类的对象用于方法的参数中:

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
}

如果超类型有一个构造函数,则必须传递参数给它。多个超类型和接口可以用逗号分隔。

通过对象表达式可以越过类的定义直接得到一个对象:

fun main(args: Array<String>) {
val site = object {
var name: String = "菜鸟教程"
var url: String = "www.runoob.com"
}
println(site.name)
println(site.url)
}

请注意,匿名对象可以用作只在本地和私有作用域中声明的类型。如果你使用匿名对象作为公有函数的 返回类型或者用作公有属性的类型,那么该函数或属性的实际类型 会是匿名对象声明的超类型,如果你没有声明任何超类型,就会是 Any。在匿名对象 中添加的成员将无法访问。

class C {
// 私有函数,所以其返回类型是匿名对象类型
private fun foo() = object {
val x: String = "x"
} // 公有函数,所以其返回类型是 Any
fun publicFoo() = object {
val x: String = "x"
} fun bar() {
val x1 = foo().x // 没问题
val x2 = publicFoo().x // 错误:未能解析的引用“x”
}
}

在对象表达中可以方便的访问到作用域中的其他变量:

fun countClicks(window: JComponent) {
var clickCount = 0
var enterCount = 0 window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
clickCount++
} override fun mouseEntered(e: MouseEvent) {
enterCount++
}
})
// ……
}

对象声明

Kotlin 使用 object 关键字来声明一个对象。

Kotlin 中我们可以方便的通过对象声明来获得一个单例。

object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
// ……
} val allDataProviders: Collection<DataProvider>
get() = // ……
}

引用该对象,我们直接使用其名称即可:

DataProviderManager.registerDataProvider(……)

当然你也可以定义一个变量来获取获取这个对象,当时当你定义两个不同的变量来获取这个对象时,你会发现你并不能得到两个不同的变量。也就是说通过这种方式,我们获得一个单例。

var data1 = DataProviderManager
var data2 = DataProviderManager
data1.name = "test"
print("data1 name = ${data2.name}")

实例

以下实例中,两个对象都输出了同一个 url 地址:

object Site {
var url:String = ""
val name: String = "菜鸟教程"
}
fun main(args: Array<String>) {
var s1 = Site
var s2 = Site
s1.url = "www.runoob.com"
println(s1.url)
println(s2.url)
}

输出结果为:

www.runoob.com
www.runoob.com

对象可以有超类型:

object DefaultListener : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
// ……
} override fun mouseEntered(e: MouseEvent) {
// ……
}
}

与对象表达式不同,当对象声明在另一个类的内部时,这个对象并不能通过外部类的实例访问到该对象,而只能通过类名来访问,同样该对象也不能直接访问到外部类的方法和变量。

class Site {
var name = "菜鸟教程"
object DeskTop{
var url = "www.runoob.com"
fun showName(){
print{"desk legs $name"} // 错误,不能访问到外部类的方法和变量
}
}
}
fun main(args: Array<String>) {
var site = Site()
site.DeskTop.url // 错误,不能通过外部类的实例访问到该对象
Site.DeskTop.url // 正确
}

伴生对象

类内部的对象声明可以用 companion 关键字标记,这样它就与外部类关联在一起,我们就可以直接通过外部类访问到对象的内部元素。

class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
} val instance = MyClass.create() // 访问到对象的内部元素

我们可以省略掉该对象的对象名,然后使用 Companion 替代需要声明的对象名:

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

注意:一个类里面只能声明一个内部关联对象,即关键字 companion 只能使用一次。

请伴生对象的成员看起来像其他语言的静态成员,但在运行时他们仍然是真实对象的实例成员。例如还可以实现接口:

interface Factory<T> {
fun create(): T
} class MyClass {
companion object : Factory<MyClass> {
override fun create(): MyClass = MyClass()
}
}

对象表达式和对象声明之间的语义差异

对象表达式和对象声明之间有一个重要的语义差别:

  • 对象表达式是在使用他们的地方立即执行的

  • 对象声明是在第一次被访问到时延迟初始化的

  • 伴生对象的初始化是在相应的类被加载(解析)时,与 Java 静态初始化器的语义相匹配

Kotlin 对象表达式和对象声明的更多相关文章

  1. Kotlin对象表达式深入解析

    嵌套类与内部类巩固: 在上一次https://www.cnblogs.com/webor2006/p/11333101.html学到了Kotlin的嵌套类与内部类,回顾一下: 而对于嵌套类: 归根结底 ...

  2. Kotlin对象表达式要点与Lambda表达式

    Kotlin对象表达式要点揭密: 在上一次https://www.cnblogs.com/webor2006/p/11352421.html中学习了Kotlin的对象表达式,它主要是解决Java中匿名 ...

  3. 第七章 函数表达式和函数声明,关于this对象 ,私有作用域(function(){})() ,私有变量和特权方法

    一:函数表达式和函数声明 1:函数声明和函数表达式的区别 ①函数声明不需要分号结尾 ②函数声明有函数提升的特点 ③函数声明后面不能跟圆括号直接调用,因为javascript将function关键字当作 ...

  4. 只有 assignment、call、increment、decrement 和 new 对象表达式可用作语句

    错误信息:只有 assignment.call.increment.decrement 和 new 对象表达式可用作语句: 分析:发生这种情况一般是在赋值时把“=”写成了“==”,例如:textBox ...

  5. Kotlin 中的伴生对象和静态成员

    用了一段时间kotlin,越用越觉得好用,爱不释手啊,留点笔记. Kotlin 中,在类中定义的对象(object)声明,可使用 companion 修饰,这样此对象(object)就是伴生对象了.类 ...

  6. python第十二天, 三元表达式, 函数对象,名称空间与作用域,函数的嵌套定义

    复习 1. 字符串的比较: 2. 函数的参数:形参与实参 3. 实参的分类:位置实参与关键字实参 4. 形参分类: 1.无值位置形参 2.有值位置形参 3.可变长位置形参 4.有无值关键字形参 5.可 ...

  7. python12--字符串的比较 函数的默认值的细节 三元表达式 函数对象 名称空间 作用域 列表与字典的推导式 四则运算 函数的嵌套

     复习   1.字符串的比较; 2.函数的参数; ******实参与形参的分类: 3.函数的嵌套调用:     # 字符串的比较#  -- 按照从左往右比较每一个字符,通过字符对应的ascii进行比较 ...

  8. Thymeleaf学习记录(8)--表达式基本对象

    基础对象 #ctx:上下文对象 /* * ====================================================================== * See ja ...

  9. EL表达式获取对象属性的原理

    EL表达式获取对象属性的原理是这样的: 以表达式${user.name}为例 EL表达式会根据name去User类里寻找这个name的get方法,此时会自动把name首字母大写并加上get前缀,一旦找 ...

随机推荐

  1. IIS网站 由http协议改变为https协议

    https://www.cnblogs.com/boosasliulin/p/6811231.html?utm_source=itdadao&utm_medium=referral

  2. java代码审计中的一些常见漏洞及其特征函数

    文章来源:https://xz.aliyun.com/t/1633 最近在先知上看到之前有篇关于java代码审计的文章总结的蛮好,记录以下特征函数,方便查阅,同时自己也会将在平时代码审计过程中积累的函 ...

  3. Zepto源码分析之一(代码结构及初始化)

    关于读源码,读jQuery自然是不错,但太过于庞大不易解读,对于小白,最好从Zepto,Lodash这样的小库入手. 这里使用的是zepto1.1.6版本为例. 自执行函数 在阅读之前,先弄清楚闭包和 ...

  4. jquery判断字符长度 数字英文算1字符 汉字算2字符

    <input type="text" maxlength="25" oninput="textlength(this)"> &l ...

  5. HTTP协议基础总结

    1,HTTP协议协议的概念:协议就是指计算机网络中,两台计算机之间进行通讯所必须共同遵守的规定和规则.HTTP协议:超文本传输协议是一种通信协议,它允许将超文本标记语言(html)文档从web服务器传 ...

  6. web框架实现购物车数量加减

    企业开发中经常是团队协作,每个人分配一个小的模块,比如说购物车模块,数量加减这一块人们首先想到的就是通过jquery实现,其实作为一个后端接口开发的程序猿也可以用自己更擅长的后端的逻辑代码来实现,那我 ...

  7. redis maxheap 51200000

    Redis无法启动 今天在启动Redis时提示以下错: C:\Java\redis2817>redis-server.exe redis.windows.conf [5268] 23 Apr 1 ...

  8. Python模拟ICMP包

    主要使用Scapy来完成 基础环境 VM1(192.168.1.226) | | VM2(192.168.1.125) vm1封装icmp包发给vm2 vm1脚本: #! /usr/bin/env p ...

  9. 【转】Windons+jenkins,构建java程序,提示C:\Windows\TEMP\jenkins5037773887088486383.bat Access is denied

    坑1: !!!前提:已设置本机电脑的账号密码, 解决方法:搜索程序services.msc-- 找到Jenkins-- 右键“属性”--登录--此账户--输入本机的账号密码--保存-- 停止Jenki ...

  10. java中存储mysql数据库时间类型

    Mysql 与 java 的时间类型 MySql的时间类型有 Java中与之对应的时间类型   date                 java.sql.Date   Datetime        ...