Kotlin基础 对象与类、接口
一.对象
1.object关键字
使用object关键字,你可以定义一个只能产生一个实列的类-单例
1.对象声明
对象声明有利于组织代码和管理状态,尤其是管理整个应用运行生命周期内的某些一致性状态。
//object 表示单例
object ApplicationSingle {
init {
print("ApplicationSingle")
}
fun setMatter(){
print("setMatter")
}
}
fun main() {
print(ApplicationSingle)
ApplicationSingle.setMatter()
}
2.对象表达式
有时候你要使用一个类的实例,只用一次,那么对于这种用完就丢的类实例,连命名都可以省了。下面这个例子中对象表达式XX类的子类,使用object关键字后,一旦实例化,该匿名类只能有唯一一个实例存在。
//父类
open class Player{
open fun load()="loading nothing.."
}
fun main(){
//对象表达式
//匿名内部类 单例 继承子类
val p=object : Player(){
override fun load()="anonymous class"
}
print(p.load())
}
3.伴生对象
如果你想将某个对象的初始化和一个类实例捆绑在一起,可以考虑使用伴生对象,使用companion修饰符,一个类定义里只能定义一个伴生对象
class ConfigMap {
//伴生对象为一 且只有调用时才会创建 也是静态
companion object{
private const val PATH="xxxx"
fun load()= File(PATH).readBytes()
}
}
fun main() {
ConfigMap.load()
}
二.类
1.嵌套类
如果一个类只对另一个类有用,那么将其嵌入到该类中并使用两个类保持在一起是合乎逻辑的,可以使用嵌套类。
class ImplantClass {
//嵌套类
class Equipment(var name:String){
fun show()= print("equipment:$name") // STOPSHIP: 2021-09-11
}
fun battle(){}
}
fun main(){
//链式调用
ImplantClass.Equipment("xiaohua").show()
}
2.数据类
1.定义
数据类,就是用来存储数据的类。 数据类直接提供了toString方法的实现。
数据类不能使用abstract,opne,sealed和inner修饰符
==符号默认情况下,比较两个普通类对象就是比较他们的引用值,数据类默认情况下提供了equals和hashCode函数的实现。、
data class Coordinate (var x:Int,var y:Int){
private val isInBounds=x>0 && y>0
//重写
override fun toString(): String {
return "Coordinate(x=$x, y=$y, isInBounds=$isInBounds)"
}
}
fun main() {
print(Coordinate(10,20))
//data 类比较的是值
//class 类比较的是内存地址
print(Coordinate(10,20)==Coordinate(10,20))
val coordinate = Coordinate(10, 20)
}
2.copy
除了重写Any类的部分函数,提供更好用的默认实现外,数据类还提供了一个函数,它可以用来方便地复制一个对象。假设你想创建一个Student实列,除了name属性,它拥有和另一个现有Student实例完全一样的属性值,如果Student是个数据类,那么复制现有Student实列就很简单了,只要调用copy函数,给想修改的属性传入值就可以了。
data class Coordinate (var x:Int,var y:Int){
private val isInBounds=x>0 && y>0
init {
println("initializing student")
}
constructor(_x:Int):this(_x,20){
}
//重写
override fun toString(): String {
return "Coordinate(x=$x, y=$y, isInBounds=$isInBounds)"
}
}
fun main() {
val coordinate = Coordinate(10, 20)
//copy 只能复制主构造函数的属性
val copy = coordinate.copy(20)
print(coordinate)
print(copy)
}
3.解构
解构声明的后台实现就是声明component1,component2等组件函数,让每个函数负责管理你想返回的一个属性数据,如果你定义一个数据类,他会自动未所有定义在主构造函数的属性添加对应的组件函数
class PlayerScore (private val experience:Int, private val level:Int) {
//普通类的结构分解 要添加逐渐函数
operator fun component1()=experience
operator fun component2()=level
}
fun main() {
val (x,y)=PlayerScore(10,20)
print("$x $y ")
//data 类可以直接结构
val (a,s)=Coordinate(10,20)
print("$a $s")
}
4.运算符重载
如果要将内置运算符应用在自定义类(普通类也可以)身上,你必须重写运算符函数,告诉编译器该如何操作自定义类。
data class Coordinate2 (var x:Int,var y:Int){
val isInBounds=x>0 && y>0
//运算符重载
operator fun plus(other:Coordinate2)=Coordinate2(x+other.x,y+other.y)
}
fun main() {
val coordinate2 = Coordinate2(10, 20)
val coordinate1 = Coordinate2(10, 20)
//这里触发重写的plus方法 把两个类的x与y相加
println(coordinate2+coordinate1 )
}
常用操作符:
| 操作符 | 函数名 | 作用 |
| + | plus | 把一个对象添加到另一个对象里 |
| += | plusAssign | 把一个对象添加到另一个对象里,然后将结果赋值给第一个对象 |
| == | equals | 如果两个对象相等,则返回true,否则返回false |
| > | compareTo | 如果左边的对象大于右边的对象,则返回true,否则返回false |
| [ ] | get | 返回集合中指定位置的元素 |
| .. | rangeTo | 创建一个range对象 |
| in | contains | 如果对象包括在集合里,则返回true |
3.枚举类
1.定义
枚举类,用来定义常量集合的一种特殊类。
enum class Direction {
EAST,
WEST,
SOUTH,
NORTH;
}
fun main() {
//这些皆为此类的实例
print(Direction.EAST)
print(Direction.EAST is Direction)
}
当然枚举类也可以定义函数。
enum class Direction(private val coordinate: Coordinate) {
EAST(Coordinate(1,0)),
WEST(Coordinate(-1,0)),
SOUTH(Coordinate(-1,0)),
NORTH(Coordinate(1,0));
//有传值需求的话可以用封装类
var licenseId :String?=null
fun updateCoordinate(playerCoordinate: Coordinate)
=Coordinate(playerCoordinate.x+coordinate.x,playerCoordinate.y+coordinate.y)
}
fun main() {
//调用函数时,使用的是枚举常量,所以应该这样调用
print(Direction.EAST.updateCoordinate(Coordinate(10,20)))
}
2.代数数据类型
可以用来表示一组子类型的闭集,枚举类就是一种简单的ADT。
enum class Direction(private val coordinate: Coordinate) {
EAST(Coordinate(1,0)),
WEST(Coordinate(-1,0)),
SOUTH(Coordinate(-1,0)),
NORTH(Coordinate(1,0));
//有传值需求的话可以用封装类
var licenseId :String?=null
fun updateCoordinate(playerCoordinate: Coordinate)
=Coordinate(playerCoordinate.x+coordinate.x,playerCoordinate.y+coordinate.y)
}
class Driver(var status : Direction){
fun checkLicense():String{
return when(status){
Direction.EAST->"没资格"
Direction.WEST->"入学"
Direction.SOUTH->"学习"
Direction.NORTH->"有资格 ${status.licenseId}"
}
}
}
fun main() {
print(Driver(Direction.EAST).checkLicense())
}
4.密封类
对于更复杂的ADT,你可以使用Kotlin的密封类(sealed class)来实现更复杂的定义,密封类可以用来定义一个类似于枚举类的ADT,但你可以更灵活地控制某个子类型。
密封类可以有诺干个子类,要继承密封类,这些子类必须和它定义在同一个文件里。
//密封
sealed class LicenseStatus2 {
//这里他没使用的必要 没有属性,如果用class的话浪费内存
object UnQualified : LicenseStatus2()
object Learning : LicenseStatus2()
class Qualified(val name:String) : LicenseStatus2()
}
class Driver2(var status :LicenseStatus2){
fun checkLicense():String{
return when(status){
is LicenseStatus2.UnQualified->"没资格"
is LicenseStatus2.Learning->"在学"
is LicenseStatus2.Qualified->"有资格,驾驶证编号:${(this.status as LicenseStatus2.Qualified).name}"
}
}
}
fun main() {
print(Driver2(LicenseStatus2.Qualified("20000817")).checkLicense())
}
二.接口
1.接口定义
Kotlin规定所有的接口属性和函数实现都要使用override关键字,接口中定义的函数并不需要open关键字修饰,他们默认就是open的。
interface Movable {
fun move()
}
class Car :Movable{
override fun move() {
}
}
2.默认实现
在接口提供默认属性的getter方法和函数实现。
interface Movable {
val maxSpeed: Int
get() = (1..500).shuffled().last()
var wheels:Int
//get() = (1..500).shuffled().last()
fun move(movable: Movable):String
}
class Car(override var wheels: Int=4) :Movable{
override val maxSpeed: Int
get() = super.maxSpeed
override fun move(movable: Movable): String {
return " "
}
}
三.抽象类
1.抽象类定义
要定义一个抽象类,你需要在定义之前加上abstract关键字,除了具体的函数实现,抽象类也可以包括抽象函数——只有定义,没有函数实现。
abstract class Gun(val range: Int) {
abstract fun trigger(): String
}
class M16(_price: Int) : Gun(range = 80) {
override fun trigger(): String {
return "M16 shooting"
}
}
fun main() {
val g: Gun = M16(120)
println(g.trigger())
}
更多推荐


所有评论(0)