学习Kotlin~类

类的field

  • 类定义的每一个属性,kotlin都会产生一个filed,一个setter(),一个getter()
  • field用来存储属性数据,不能直接定义,kotlin会封装,保护它里面数据,只暴露给getter和setter使用
  • 只有可变属性才有setter方法
  • 需要控制如何读取属性数据时,可以自定义它们
	class Player {
	    //针对每定义一个属性,都会有一个field,get(),set()
	    var name = "abc "
	        get() = field.capitalize()
	        set(v) {
	            field = v.trim()
	        }
	
	    //计算属性是通过一个覆盖的get()和set()来计算
	    var rolledValue = 0
	        get() = (1..6).shuffled().first()
	        set(v) {
	            field = v + 11
	        }
	}

类初始化

主构造函数

  • 主构造函数里,临时变量通常都会以下划线开头名字命名
	/**
	 * 主构造函数里,临时变量,通常都会以下划线开头的名字命名
	 */
	class Player(
	    _name: String,
	    _age: Int,
	    _isNormal: Boolean
	) {
	
	    var name = _name
	        get() = field.capitalize()
	        private set(value) {
	            field = value.trim();
	        }
	    var age = _age;
	    var isNormal = _isNormal;
	
	}
  • 主构造函数里定义属性,直接用一个变量和类型指定属性
	/**
	 * 在主构造函数里直接定义属性
	 */
	class Player1(
	    _name: String,
	    var age: Int,
	    val isNormal: Boolean
	) {
	
	    var name = _name
	        get() = field.capitalize();
	        private set(value) {
	            field = value.trim();
	        }
	
	}
  • 主构造函数里定义属性,可以给构造函数参数指定默认值
	/**
	 * 在主构造函数里直接定义属性
	 */
	class Player1(
	    _name: String,
	    var age: Int,
	    val isNormal: Boolean = true
	) {
	
	    var name = _name
	        get() = field.capitalize();
	        private set(value) {
	            field = value.trim();
	        }
	
	}

次构造函数

  • 可以定义多个次构造函数来配置不同的参数组合

  • 使用次构造函数,定义初始化代码逻辑

	/**
	 * 次构造函数
	 */
	class Player2(
	    _name: String,
	    var age: Int,
	    val isNormal: Boolean
	) {
	
	    var name = _name
	        get() = field.capitalize();
	        private set(value) {
	            field = value.trim();
	        }
	
	    //次构造函数
	    constructor(name: String) :
	            this(name, age = 100, isNormal = false) {
	        this.name = name.toUpperCase();
	    }
	}

初始化块

  • 初始化块可以设置变量或值,以及有效性检查

  • 初始化块代码会在构造类实例时执行

	/**
	 * 初始化块init,会在构造类实例时执行
	 */
	class Player3(
	    _name: String,
	    var age: Int = 20,
	    private val isNormal: Boolean
	) {
	    var name = _name
	        get() = field.capitalize();
	        private set(value) {
	            field = value.trim();
	        }
	
	    init {
	        require(age > 0) { "age must be positive" }
	        require(name.isNotBlank()) { "player must have a name" }//false会执行后面闭包
	    }
	}
初始化顺序
主构造函数里声明的属性
类级别的属性赋值
init初始化块里的属性赋值和函数调用
次构造函数里属性赋值和函数调用

在这里插入图片描述

延迟初始化
  • 使用lateinit关键字相当于做了一个约定:再用它之前负责初始化
  • 只要无法确认lateinit变量是否完成初始化,可以执行isInitialized检查是否完成了初始化
  • 一般变量必须要初始化,但是使用lateinit以后可以先不用初始化,等到用的时候再去赋值
	/**
	 * 延迟初始化 lateinit关键字相当于做了一个约定:再用它之前负责初始化
	 * 只要无法确认lateinit变量是否完成初始化,可以执行isInitialized检查
	 */
	class Player5 {
	    lateinit var equipment: String
	    fun ready() {
	        equipment = "sharp knife"
	    }
	
	    //::操作符 使用变量的引用
	    fun battle() {
	        if (::equipment.isInitialized) println(equipment)
	    }
	}
惰性初始化
  • 暂时不初始化某个变量,直到首次使用它,这个叫惰性初始化
	/**
	 * 惰性初始化,可以暂时不初始化某个变量,直到首次使用它才初始化
	 */
	class Player6(_name: String) {
	    var name = _name
	
	    //val config =  loadConfig() ;//这种方式config变量直接初始化了
	    val config by lazy { loadConfig() }//这里使用by lazy就是惰性初始化
	
	    private fun loadConfig(): String {
	        println("loading...")
	        return "xxx"
	    }
	}
	
	fun main() {
	    //创建对象的时候,就会给所有的对象初始化,
	    //但是使用了by lazy以后的变量就可以不初始化,等到调用的时候自动初始化
	    val p = Player6("jack")
	    Thread.sleep(3000)
	    println(p.config)
	}

继承

  • 类默认都是封闭的,要想让某个类开放继承,必须使用open关键字修饰它
	/**
	 * 类默认是关闭的,要让某个类开放继承,必须使用open关键字修饰它
	 */
	open class Product(val name: String) {
	    fun description() = "Product $name"
	    open fun load() = "Nothing..."
	
	}

函数重载

  • 父类的函数也要以open关键字修饰,子类才能覆盖它
	//继承
	class LuxuryProduct(val _name: String) : Product(_name) {
	    /**
	     * 父类的函数也要以open关键字修饰,子类才能覆盖它
	     */
	    override fun load() = "LuxuryProduct loading ..."
	
	    fun sale(product: Product) {
	        println(product.description())
	    }
	}

类型检测

  • 每一个类都会继承一个共同的叫作Any的超类
is运算符
  • kotlin的is运算符是个不错的工具,可以用来检查某个对象的类型
	val p = LuxuryProduct("jack")
	/**
	 * is运算符可以用来检查某个元素类型
	 */
	println(p is LuxuryProduct)
	println(p is Product)
as运算符
  • as操作符声明,这是一个类型转换

  • 只要能确定any is父类条件检查属实,它就会将any当做子类类型对待,可以不经过as转换

	val p = LuxuryProduct("jack")
	/**
	 * as操作符,类型转换
	 */
	p.sale(p as LuxuryProduct)
	/**
	 * 智能类型转换
	 */
	p.sale(p)//这里不用转,默认是子类

单例对象

object关键字

  • 使用object关键字,可以定义一个只能产生一个实例的类-单例
  • 使用object关键字有三种方式
对象声明
  • 对象声明有利于组织代码和管理状态,尤其是管理整个应用运行生命周期内某些一致性状态
	/**
	 * object关键字 对象声明 这是一个单例对象
	 */
	object ApplicationConfig {
	    //第一次创建时候执行
	    init {
	        println("loading config...")
	    }
	
	    fun setSomething() {
	        println("setSomething")
	    }
	}
	
	fun main() {
	    ApplicationConfig.setSomething()
	    println(ApplicationConfig)
	    println(ApplicationConfig)
	}
对象表达式
  • 可以使用object声明某个类的子类实例对象,不用在重新写一个新类;创建对象时候,对象的类名也省略了
	open class Player {
	    open fun load() = "loading nothing."
	}
	
	fun main() {
	    /**
	     * object关键字,声明一个匿名实例对象,也是单例
	     * 这个对象,是 Player的子类对象,子类无需定义一个名字
	     */
	    val p = object : Player() {
	        override fun load() = "anonymous class load..."
	    }
	    println(p.load())
	
	}
伴生对象
  • 一个类里只能有一个伴生对象
  • 想将某个对象的初始化和一个类实例捆绑在一起,可以考虑伴生对象,使用companion修饰符
	import java.io.File
	
	/**
	 * object 关键字 伴生对象
	 * 使用companion修饰,一个类只能有一个伴生对象
	 */
	open class ConfigMap {
	    companion object {
	        /**
	         * 只有初始化ConfigMap类或调用load函数时,伴生对象的内容才会载入。
	         * 而且无论实例化ConfigMap类多少次,这个伴生对象始终只有一个实例存在。
	         */
	        private const val PATH = "xxx"
	
	        fun load() = File(PATH).readBytes()
	    }
	}
	
	fun main() {
	    println(ConfigMap.load())
	}

运算符重载

  • 要将内置运算符应用在自定义类身上,必须重写运算符函数,告诉编译器如何操作自定义类
操作符函数名作用
+plus把一个对象添加到另一个对象里
+=plusAssign把一个对象添加到另一个对象里,然后将结果赋值给第一个对象
==equals两个对象相等则返回true,否则false
>compareTo左边对象大于右边对象返回true,否则返回false
[]get返回集合中指定位置的元素
rangeTo创建一个range对象
incontains如果对象包含在集合里,则返回true
	class Coordinate(var x: Int, var y: Int) {
	
	//    operator fun plus(c: Coordinate): Coordinate {
	//        return Coordinate(this.x + c.x, this.y + c.y);
	//    }
	
	    operator fun plusAssign(c: Coordinate) {
	        this.x = this.x + c.x;
	        this.y = this.y + c.y;
	    }
	    
	}
	
	fun main() {
	    var a = Coordinate(10, 20);
	    var c = Coordinate(1, 2);
	//    println(c + a)
	    a += c
	}

嵌套类

  • 如果一个类对另一个类有用,那么将其嵌入到该类中,并保持在一起是合乎逻辑的
	/**
	 * 嵌套类
	 */
	class Player3() {
	
	    class Equipment(val name: String) {
	        fun show() = println("equipment $name");
	    }
	
	    fun battle() {
	        Equipment("AK7").show();
	    }
	
	}
	
	fun main() {
	    Player3().battle();
	}

数据类

数据类的对象

  • 数据类是专门用来设计存储数据的类
  • 数据类提供了toString的个性化实现
  • ==符号默认情况下,比较对象就是比较它们的引用值,数据类提供了equals和hashCode个性化实现
	/**
	 * 数据类, 专门用来存储数据的类
	 * 数据类提供了toString的个性化实现
	 * ==符号默认情况下,比较对象就是比较它们的引用,
	 * 数据类提供了equals和hashCode的个性化实现
	 */
	data class Coordinate(var x: Int, var y: Int) {
	    //坐标值是否是正值
	    val isInBounds = x >= 0 && y >= 0
	}
	
	fun main() {
	    //重写了toString方法
	    println(Coordinate(1, 5))//Coordinate(x=1, y=5)
	    //本身重写了equals和hashCode所以两个对象相等
	    println(Coordinate(1, 5) == Coordinate(1, 5))//true
	
	}

数据类的copy方法

  • 使用数据类的copy方法默认的是主构造函数,复制一个对象
	/**
	 * 数据类提供了一个copy函数可以用来方便的复制对象
	 */
	data class Student(var name: String, var age: Int) {
	    var score = 10
	    private val hobby = "music"
	    val subject: String
	
	    init {
	        println("initializing student")
	        subject = "math"
	    }
	
	    constructor(_name: String) : this(_name, 10) {
	        score = 20
	    }
	
	    override fun toString(): String {
	        return "Student(name='$name', age=$age, score=$score, hobby='$hobby', subject='$subject')"
	    }
	
	}
	
	fun main() {
	    val s = Student("Jack")
	    println(s)
	    val copy = s.copy("Rose")//这里复制对象默认使用的主构造函数
	    println(copy)
	}

数据类的解构声明

  • 结构声明的后台实现就是声明component1、component2等若干个组件函数,让每个函数负责管理你想返回的一个属性数据,类似这样
	public final int component1() {
	   return this.x;
	}
	
	public final int component2() {
	   return this.y;
	}
	/**
	 * 结构声明的后台实现就是声明component1,component2等若干个组件函数,让每个函数
	 * 负责管理你想返回的一个属性数据
	 */
	class PlayerScore(val experience: Int, val level: Int) {
	    operator fun component1() = experience
	    operator fun component2() = level;
	}
	
	fun main() {
	    val (x, y) = PlayerScore(10, 5)
	    println(x)
	    println(y)
	}
  • 如果定义一个数据类,它会自动为定义在主构造函数的属性添加对应的组件函数
	data class Coordinate(var x: Int, var y: Int) {
	    //坐标值是否是正值
	    val isInBounds = x >= 0 && y >= 0
	}
	
	fun main() {
	    /**
	     * 数据类天生支持解构语法,数据类默认会生成组件函数component1
	     */
	    val (x, y) = Coordinate(10, 5)
	    println(x)//10
	    println(y)//5
	}

数据类的使用条件

  • 经常需要比较、复制、打印自身内容的类,数据类适合它们;

  • 数据类使用有以下三个条件

    • 数据类必须有至少带一个参数的主构造函数
    • 数据类主构造函数的参数必须是val或var
    • 数据类不能使用abstract、open、sealed和inner修饰符

枚举类

  • 用来定义常量集合的一种特殊类
	enum class Direction {
	    EAST,
	    WEST,
	    SOUTH,
	    NORTH
	}
  • 枚举类也可以定义函数
	/**
	 * 枚举类也可以定义函数
	 */
	enum class Direction2(private val coordinate: Coordinate) {
	    //枚举类构造函数传入对象,那么每个枚举类的对象也要传入构造对象
	    EAST(Coordinate(5, -1)),
	    WEST(Coordinate(1, 0)),
	    SOUTH(Coordinate(0, 1)),
	    NORTH(Coordinate(-1, 0));
	
	    fun updateCoordinate(p: Coordinate) = Coordinate(p.x + coordinate.x, p.y + coordinate.y)
	
	}
	
	class Coordinate(val x: Int, val y: Int) {
	    override fun toString(): String {
	        return "Coordinate(x=$x, y=$y)"
	    }
	}
	
	fun main() {
	    println(Direction.EAST)
	    //调用函数时,使用的是枚举常量,所以这样调用
	    println(Direction2.EAST.updateCoordinate(Coordinate(1, 2)))
	}

下面使用枚举类实现一个驾照类和司机类;

	/**
	 * 代数数据类型
	 */
	enum class LicenseStatus {
	    UNQUALIFIED,//没资格
	    LEARNING,//正在学
	    QUALIFIED;//有驾照
	
	    //驾驶证的id,这里的话只有有驾照才有其他的都不可能有
	   // var licenseId: String? = null;
	
	}
	
	class Driver(var status: LicenseStatus) {
	    fun checkLicense(): String {
	        return when (status) {
	            LicenseStatus.UNQUALIFIED -> "没资格"
	            LicenseStatus.LEARNING -> "在学"
	            LicenseStatus.QUALIFIED -> "有资格"
	        }
	    }
	}

密封类

  • 枚举类和密封类都是代数数据类型(ADT);

在上面的枚举类中不可能正常带有驾照的id,为了实现这种需求,我们使用了密封类

  • 密封类可以有若干个子类,若要继承密封类,这些子类必须和它定义在同一个文件里;
	/**
	 * 密封类
	 * 可以有若干个子类,要继承密封类,这些子类必须和它定义在同一个文件里
	 */
	sealed class LicenseStatus {
	    //这种情况使用object单例,因为没有属性状态
	    object UnQualified : LicenseStatus2()
	    object Learning : LicenseStatus2()
	
	    //有属性状态,所以使用类
	    class Qualified(val licenseId: String) : LicenseStatus2()
	}
	
	class Driver(var status: LicenseStatus2) {
	    fun checkLicense(): String {
	        //编译器会自动检测是否有遗漏
	        return when (status) {
	            LicenseStatus2.UnQualified -> "没资格"
	            LicenseStatus2.Learning -> "在学"
	            is LicenseStatus2.Qualified ->
	                "有资格,驾驶证编号:" + "${(this.status as LicenseStatus2.Qualified).licenseId}"
	        }
	    }
	}

使用了密封类,就可以正常展示驾照的Id了;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/34288.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

探索 Jetson Nano 为 myCobot 280 机械臂提供的强大功能

探索 Jetson Nano 为 myCobot 280 提供的强大功能,机器人技术的一个有前途的组合 介绍 近年来,科学技术的发展给我们的生活带来了许多新的产品和服务,包括机器人在各个领域的集成。机器人已经成为我们生活中必不可少的一部分,从…

Vim 自定义配色

本文首发于我的个人博客,欢迎点击访问,无广告节面简洁! 最近重新开始学习Vim装上了WSL2,但发现Windows Terminal和vim的组合还是有很多问题需要解决的,由其默认的配色在某些状态下根本看不清字体,所以折腾…

Nginx | 苹果电脑Mac安装和验证Nginx服务过程记录

common wx:CodingTechWork,一起学习进步。 引言 本文主要总结如何在Mac电脑上进行Nginx服务的安装,重点讲解使用brew命令进行安装和验证的过程及问题记录。 安装步骤 安装过程记录 查看nginx信息 首先使用命令brew info nginx进行本机ng…

《Pytorch深度学习和图神经网络(卷 1)》学习笔记——第七章

这一章内容有点丰富,多用了一些时间,实例就有四五个。 这章内容是真多啊!(学完之后又回到开头感叹) 大脑分级处理机制: 将图像从基础像素到局部信息再到整体信息 即将图片由低级特征到高级特征进行逐级计…

基于群组实现从 Azure AD 到极狐GitLab 的单点登录

目录 配置单点登录 在 Azure AD 中创建企业应用 SAML 基础配置 配置 Azure “Attributes & Claims” 配置用户同步 在极狐GitLab 创建 SCIM Token 配置 Azure Provisioning Azure 手动用户预配 测试单点登录 Azure 自动用户同步 配置群组同步 配置 SAML 群组链…

打jar包

pom文件指定打包的类型是jar&#xff0c;并指定启动主类 <packaging>jar</packaging><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>…

什么条件下会出现死锁,如何避免?

文章目录 一、什么是死锁二、产生死锁的原因&#xff1a;三、如何避免死锁&#xff1a; 一、什么是死锁 死锁&#xff0c;简单来说就是两个或者两个以上的线程在执行过程中&#xff0c;去争夺同一个共享资源导致相互等待的现象。如果没有外部干预&#xff0c;线程会一直处于阻塞…

uniapp封装门票等票务样式

先看效果图 ticketpage组件引用后&#xff0c;根据父级背景颜色改变镂空的颜色,空组件只有中间镂空的样式&#xff0c;上面是插槽heaer,下面内容是插槽content&#xff0c;可以自定义自己的内容和样式。我实现的最终效果是用的uview组件&#xff0c;如果复现需要项目引入。可…

Nginx负载均衡与动静分离

一、Nginx负载均衡&#xff1a; 1.概述&#xff1a; Nginx是一款http服务器软件&#xff0c;支持高达50000个并发连接数的响应。 &#xff08;1&#xff09;拥有强大的处理静态资源的能力。 &#xff08;2&#xff09;运行稳定。 &#xff08;3&#xff09;CPU&#xff0c…

【Unity3D编辑器开发】Unity3D中初次尝试使用PropertyDrawer属性

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 前段时间一直比较忙&#xff0c;没有时间更新博客&#xff0c;…

2011年全国硕士研究生入学统一考试管理类专业学位联考逻辑试题——纯享题目版

&#x1f3e0;个人主页&#xff1a;fo安方的博客✨ &#x1f482;个人简历&#xff1a;大家好&#xff0c;我是fo安方&#xff0c;考取过HCIE Cloud Computing、CCIE Security、CISP、RHCE、CCNP RS、PEST 3等证书。&#x1f433; &#x1f495;兴趣爱好&#xff1a;b站天天刷&…

tomcat接入skywalking

tomcat接入skywalking 一、说明二、步骤2.1 准备java-agent包2.2 tomcat部署2.2.1 下载2.2.2 tomcat修改catalina.sh文件2.2.3 tomcat修改启动端口2.2.4 启动tomcat 三、验证四、问题排查4.1 tomcat的启动日志 一、说明 服务器中已经运行着skywalking&#xff0c;准备在同一台…

7-WebApis-5

Web APIs - 5 目标&#xff1a; 能够利用JS操作浏览器,具备利用本地存储实现学生就业表的能力 BOM操作综合案例 js组成 JavaScript的组成 ECMAScript: 规定了js基础语法核心知识。比如&#xff1a;变量、分支语句、循环语句、对象等等 Web APIs : DOM 文档对象模型&#xff…

2023全云在线联合微软AIGC专场沙龙:人工智能与企业创新,促进创造力的数字化转型

6月29日&#xff0c;由全云在线平台和微软联合主办的人工智能与企业创新&#xff1a;促进创造力的数字化转型——2023AIGC微软专场沙龙在广州天河区正佳万豪酒店举行。 关于2023AIGC微软专场沙龙 GPT翻开了AGI新的一页&#xff0c;也翻开了各行各业的新篇章。 2022年11月30日…

使用Jmeter读取和使用Redis数据

目录 前言 缓存 Redis服务和客户端安装 Jmeter使用Redis 前言 在使用 JMeter 进行性能测试时&#xff0c;有时需要读取和使用 Redis 数据。Redis 是一个开源的内存数据存储系统&#xff0c;常用于缓存、消息队列和数据存储等场景。 缓存 Web系统通常使用数据库来存储数据…

性能测试讲解超详细Jmeter

目录 什么是性能 性能测试的目的 功能测试和性能测试 基准测试 负载测试 稳定性测试 压力测试 并发测试 总结 性能测试指标 响应时间 并发数 吞吐量 点击数 错误率 资源使用率 总结 性能测试流程 性能测试需求分析 性能测试计划和方案 ​编辑性能测试用例​编辑 性…

【MySQL】MySQL数据库,RDBMS 术语,使用说明和报错解决的详细讲解

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f…

CommonJS 和 ES6 module

本文主要自己觉得要记录的点记录下来,不耽误大家时间&#xff0c;会持续更新。 Module对象 Module {id: xxx/demo/1.js, //加载文件的绝对路径path: xxx/demo,// 加载文件所在目录的绝对路径exports: [Function (anonymous)],filename: xxx/demo/1.js,加载文件的绝对路径load…

蓝桥杯专题-试题版-【圆的面积】【字符串对比】【字母图形】【核桃的数量】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

Lesson1-1:OpenCV简介

图像处理 学习目标 了解图像的起源知道数字图像的表示 1 图像的起源 1.1 图像是什么 图像是人类视觉的基础&#xff0c;是自然景物的客观反映&#xff0c;是人类认识世界和人类本身的重要源泉。“图”是物体反射或透射光的分布&#xff0c;“像“是人的视觉系统所接受的图在…