当前位置: 首页 > news >正文

13:kotlin类和对象 -- 属性(Properties)

定义属性

类属性可使用varval定义

class Address {var name: String = "Holmes, Sherlock"var street: String = "Baker"var city: String = "London"var state: String? = nullvar zip: String = "123456"
}

属性使用

fun copyAddress(address: Address): Address {val result = Address()result.name = address.name result.street = address.street// ...return result
}

Getters/setters

完整的定义一个属性的公式如下

var <propertyName>[: <PropertyType>] [= <property_initializer>][<getter>][<setter>]val <propertyName>[: <PropertyType>] [= <property_initializer>][<getter>]

[]中的内容都是可选的

var initialized = 1 // 有类型Int, 默认getter和默认setter
val simple: Int? // 有类型Int, 默认getter, 必须在构造函数中初始化
val inferredType = 1 // 类型Int,默认getter

如果定义了getter,则每次访问该属性时都会调用

class Rectangle(val width: Int, val height: Int) {val area: Int // 属性Int在这里是可选的,因为可以从getter中推断出类型get() = this.width * this.height
}

val area get() = this.width * this.height

如果自定义了setter,除属性初始化除外,每次属性赋值时都将调用它

var stringRepresentation: Stringget() = this.toString()set(value) {setDataFromString(value) // 解析字符串并把值赋给其他字段}

如果想要一个var类型的属性不能在外部被修改,可以使用private或者@Inject修饰setter方法

var setterVisibility: String = "abc"private set var setterWithAnnotation: Any? = null@Inject set // 官方说可以使用这个,但是未找到这个怎么用,说找不到这个注解

Backing fields

我称为隐藏字段

官方介绍是这样说的,让我觉得头大

In Kotlin, a field is only used as a part of a property to hold its value in memory. Fields cannot be declared directly. However, when a property needs a backing field, Kotlin provides it automatically. This backing field can be referenced in the accessors using the field identifier

我理解的意思是:在kotlin中,字段(field)并不是类中定义的属性,而是用来存属性值的一个东西。不能手动定义字段,当在访问器中需要用到字段的时候,kotlin已经为我们自动的定义好了,直接用就行了,字段用field关键字表示

class Rectangle() {var test = 4set(value) {field = value}get() = field
}

实例中,field,也就是字段,指向存储4的位置,而不是test

如果在访问器中不使用field,而是使用属性本身会怎样

class Rectangle() {var test = 4get() = test
}fun main() {val rectangle = Rectangle()println(rectangle.test)
}

在这里插入图片描述
idea提示这是一个递归调用,第13行也标志是一个递归调用。如果执行了代码则会报错Exception in thread "main" java.lang.StackOverflowError,这是因为在访问器中使用了属性名,而使用属性名会调用访问器,循环递归后内存溢出,所以需要使用field来代指属性,避免这个问题,就目前看field更像一个补丁

Backing properties

如果做一些不适合隐藏字段的事情,可以使用隐藏属性

class Rectangle() {private var _table: Map<String, Int>? = nullval table: Map<String, Int>get() {if (_table == null) {_table = HashMap() // Type parameters are inferred}return _table ?: throw AssertionError("Set to null by another thread")}
}

在JVM上:使用默认gettersetter访问私有属性做了优化,以避免函数调用开销。

编译时常量(Compile-time constants)

如果只读属性的值在编译时已知,则使用const修饰符将其标记为编译时常量。此类属性需要满足以下要求:

  • 它必须是顶级属性,或者是对象或伴生对象的成员。
  • 它必须使用String或原始类型的值进行初始化
  • 它不能是自定义getter

编译器将内联常量的用法,将对常量的引用替换为其实际值。但是,该字段不会被删除,因此可以使用反射与之交互

/*** 顶级变量*/
const val SUBSYSTEM_DEPRECATED: String = "方法过期了"class Demo() {@Deprecated(SUBSYSTEM_DEPRECATED) // 注解中可使用const修饰的属性fun foo() { }
}

延迟初始化属性和变量(Late-initialized properties and variables)

通常,声明为非空类型的属性必须在构造函数中初始化。然而,这样做并不方便。例如,属性可以通过依赖注入进行初始化,或者在单元测试的设置方法中进行初始化。

为了处理这种情况,可以使用lateinit修饰符标记属性

public class MyTest {lateinit var subject: TestSubject   // 延迟初始化 subject@SetUp fun setup() {subject = TestSubject()}@Test fun test() {subject.method()}
}

可以用在类的主体内声明的var属性(不在主构造函数中,且没有自定义的getter或setter时),以及顶层属性和局部变量。属性或变量的类型必须是非空的,并且不能是原始类型

在初始化之前访问lateinit属性会抛出一个特殊的异常,清楚地标识被访问的属性以及它尚未被初始化的事实

检查是否已经初始化

使用.isInitialized方法检查是否已经初始化

class TestSubject() {fun method() {}
}class MyTest {lateinit var subject: TestSubject fun test() {if (this::subject.isInitialized)subject.method()}
}

重写属性(Overriding properties)

下章讲解

委托属性(Delegated properties)

后边文章中再讲

相关文章:

  • Linux运行jmeter报错java.sql.SQLException:Cannot create PoolableConnectionFactory
  • 笔记二十六、React中路由懒加载的扩展使用
  • 分享从零开始学习网络设备配置--任务4.3 使用动态路由RIPng实现网络连通
  • 力扣:182. 查找重复的电子邮箱(Python3)
  • 新金融时代、AMCAP谱写财富梦想新篇章
  • 特权FPGA 第二章 笔记
  • 「Verilog学习笔记」数据累加输出
  • WIN10系统自带硬盘测速工具使用
  • 2023.11.28 使用tensorflow进行“三好“权重分析
  • LeetCode(34)有效的数独【矩阵】【中等】
  • 【PyTorch】(三)模型的创建、参数初始化、保存和加载
  • html实现360度产品预览(附源码)
  • 使用electron工具打包web端到PC端应用程序
  • PLC通过lora网关采集温室大棚温湿度数据
  • antDesignPro a-table样式二次封装
  • Android 控件背景颜色处理
  • Angular 响应式表单之下拉框
  • Effective Java 笔记(一)
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • Laravel 中的一个后期静态绑定
  • orm2 中文文档 3.1 模型属性
  • Promise面试题,控制异步流程
  • python 装饰器(一)
  • Python连接Oracle
  • 浮动相关
  • 深度学习入门:10门免费线上课程推荐
  • 深入浅出webpack学习(1)--核心概念
  • 思否第一天
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 无服务器化是企业 IT 架构的未来吗?
  • 原生 js 实现移动端 Touch 滑动反弹
  • 2017年360最后一道编程题
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • #Z2294. 打印树的直径
  • #基础#使用Jupyter进行Notebook的转换 .ipynb文件导出为.md文件
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • (13):Silverlight 2 数据与通信之WebRequest
  • (14)Hive调优——合并小文件
  • (175)FPGA门控时钟技术
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (C#)一个最简单的链表类
  • (day 12)JavaScript学习笔记(数组3)
  • (二)【Jmeter】专栏实战项目靶场drupal部署
  • (简单) HDU 2612 Find a way,BFS。
  • (一)pytest自动化测试框架之生成测试报告(mac系统)
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • .NET多线程执行函数
  • .NET面试题(二)
  • .Net面试题4
  • /*在DataTable中更新、删除数据*/
  • @PreAuthorize注解
  • @RequestMapping-占位符映射
  • [20170728]oracle保留字.txt
  • [2019/05/17]解决springboot测试List接口时JSON传参异常