【Kotlin】类和对象

1 前言

        Kotlin 是面向对象编程语言,与 Java 语言类似,都有类、对象、属性、构造函数、成员函数,都有封装、继承、多态三大特性,不同点如下。

  • Java 有静态(static)代码块,Kotlin 没有;
  • Java 有静态(static)函数,Kotlin 没有;
  • Java 构造函数名与类名相同,Kotlin 构造函数名为 constructor;
  • Kotlin 有初始化代码块(init),Java 没有;
  • Kotlin 有主构造函数,Java 没有。

        在包下面右键,依次点击【New → Kotlin Class/File】,输入类名后,创建 Kotlin 类文件。

         如下,创建了一个 Student.kt 文件。

package com.zhyan8.kotlinStudyclass Student {
}

        笔者为简化代码,将定义的类与 main 函数放在同一个文件中了。

2 类的结构

        如下,Student 类是一个自定义的类,里面包含了一个类的基本结构。

fun main() {var stu1 = Student()stu1.study()println("-----------------------------------------")var stu2 = Student("li si", 23)
}class Student {private var name: String = "zhang san" // 属性get() { // name的getter函数return field}set(value) { // name的setter函数field = value}private var age: Int = 18 // 属性init { // 初始化代码块, 在构造函数前执行println("Student init, name=$name, age=$age")}constructor() { // 无参构造函数println("create-1, name=$name, age=$age")}constructor(name: String, age: Int) { // 有参构造函数println("create-2, name=$name, age=$age")this.name = namethis.age = age}fun study() { // 成员函数println("study...")}
}

        说明:init 代码块可以有多个,按照从前往后的顺序执行;上述构造函数都是次要构造函数,第 3 节中会介绍主构造函数。

        运行程序后,打印如下。

Student init, name=zhang san, age=18
create-1, name=zhang san, age=18
study...
-----------------------------------------
Student init, name=zhang san, age=18
create-2, name=li si, age=23

3 主构造函数

        主构造函数是紧接在类名后面的构造函数,次要构造函数是类体内部定义的构造函数,它们的区别如下。

  • 主构造函数:主构造函数只能存在一个,只有函数声明,没有函数体,可以在入参中定义类的属性,会自动进行类属性的初始化赋值。
  • 次要构造函数:次要构造函数可以存在多个,可以自定义函数体,也可以无函数体,不能在入参中定义类属性,当类有主构造函数时,所有次要构造函数必须直接或间接地调用主构造函数。

3.1 无参主构造函数

fun main() {var stu1 = Student()println("-----------------------------------------")var stu2 = Student("zhang san")
}class Student() { // 等价与: class Student constructor()init { // 初始化代码块, 在构造函数前执行println("init")}constructor(name: String): this() {println("constructor, name=$name")}
}

        运行程序后,打印如下。

init
-----------------------------------------
init
constructor, name=zhang san

        class Student() 等价于 class Student constructor(),如果需要对主构造函数的权限进行控制,可以修改如下。

class Student private constructor() {...
}

3.2 有参主构造函数(普通参数)

fun main() {var stu1 = Student("xiao ming", 23)println("-----------------------------------------")// stu1.name // 编译报错, name不是成员属性var stu2 = Student()
}class Student(name: String, age: Int) {init {println("init, name=$name, age=$age")}constructor(): this("zhang san", 18) {println("constructor")}
}

        运行程序后,打印如下。

init, name=xiao ming, age=23
-----------------------------------------
init, name=zhang san, age=18
constructor

3.3 有参主构造函数(成员属性)

fun main() {var stu1 = Student("xiao ming", 23)println("stu1.name=${stu1.name}, stu1.age=${stu1.age}")println("-----------------------------------------")var stu2 = Student()println("stu2.name=${stu2.name}, stu2.age=${stu2.age}")
}class Student(var name: String, var age: Int) {init {println("init, name=$name, age=$age")}constructor(): this("zhang san", 18) {println("constructor")}
}

        说明:在主构造函数中,通过给入参添加 var(变量)或 val(常量)修饰,使得参数变为成员属性;在次要构造函数中,不能给入参添加 var 或 val 修饰。

        运行程序后,打印如下。

init, name=xiao ming, age=23
stu1.name=xiao ming, stu1.age=23
-----------------------------------------
init, name=zhang san, age=18
constructor
stu2.name=zhang san, stu2.age=18

        如果用户想修改入参属性的权限,可以在 var 或 val 前面添加权限修饰符。

class Student(private val name: String, protected var age: Int) {...
}

4 封装

        封装是指将相关联的属性和函数封装到同一个类中,并且可以控制这些属性和函数的访问权限,它通过隐藏内部细节和提供清晰的接口,提高了代码的安全性、可维护性和可理解性,它是面向对象编程中的重要概念之一。

        在 Kotlin 中,有四种访问权限修饰符:private、protected、internal 和 public。这些修饰符控制了代码中类、函数、属性等成员的可见性和访问权限。

  • private:最严格的访问权限,只在声明它的类或文件内可见。
  • protected:与 Java 中的 protected 类似,不同之处在于 Kotlin 中 protected 修饰的成员仅对其子类可见,但不一定在同一个文件中可见。另外,protected 在 Kotlin 中不能直接应用于顶层函数和属性(直接定义在文件中的函数和属性,而不是在类中定义的)。
  • internal:模块内可见(模块是编译在一起的一组 Kotlin 文件),internal 修饰的成员对于同一模块中的任何其他代码都是可见的,但对于其他模块中的代码是不可见的。
  • public:最宽松的访问权限,public 成员可以被任何地方的代码访问,如果没有指定访问修饰符,默认为 public。

5 继承

        继承是指一个类(称为子类或派生类)基于另一个类(称为父类或基类)创建新类,子类继承了父类的属性和函数,并且可以在此基础上进行扩展或修改,它是面向对象编程中的重要概念之一。在 Kotlin 中,继承使用冒号(:)来表示,Any 类是所有类的基类。

        类的初始化顺序如下。

  1. 父类主构造函数
  2. 父类 init 代码块
  3. 父类次要构造函数
  4. 子类主构造函数
  5. 子类 init 代码块
  6. 子类次要构造函数

5.1 子类无主构造函数

fun main() {var stu = Student("zhang san", 23, 1001)
}open class People(var name: String) {init {println("People init, name=$name") // 1}constructor(name: String, age: Int): this(name) {println("People constructor, name=$name, age=$age") // 2}
}class Student : People {init {println("Student init, name=$name") // 3 (此处不能访问age和id)}constructor(name: String, age: Int, id: Int) : super(name, age) {println("Student constructor, name=$name, age=$age, id=$id") // 4}
}

        说明:子类必须直接或间接调用一下父类的一个构造函数,否则编译报错。

        运行程序后,打印如下。

People init, name=zhang san
People constructor, name=zhang san, age=23
Student init, name=zhang san
Student constructor, name=zhang san, age=23, id=1001

5.2 子类有主构造函数

fun main() {var stu = Student("zhang san", 23, 1001)
}open class People(var name: String) {init {println("People init, name=$name") // 1}constructor(name: String, age: Int): this(name) {println("People constructor, name=$name, age=$age") // 2}
}class Student(name: String, var age: Int) : People(name, age) {init {println("Student init, name=$name, age=$age") // 3 (此处不能访问id)}constructor(name: String, age: Int, id: Int): this(name, age) {println("Student constructor, name=$name, age=$age, id=$id") // 4}
}

        说明:子类必须直接或间接调用一下父类的一个构造函数,否则编译报错;当子类中有主构造函数时,子类中的次要构造函数。  

        运行程序后,打印如下。

People init, name=zhang san
People constructor, name=zhang san, age=23
Student init, name=zhang san, age=23
Student constructor, name=zhang san, age=23, id=1001

6 多态

        多态是指同一个函数可以在不同的对象上表现出不同的行为,这种行为通常通过继承和接口来实现。多态使得代码更加灵活和可扩展,是面向对象编程中的重要概念之一。

6.1 覆盖函数

fun main() {var peo: People = Student("li si", 25, 1002)peo.say()
}open class People(var name: String, var age: Int) {init {println("People init, name=$name, age=$age")}open fun say() {println("People say")}
}class Student(name: String, age: Int, var id: Int) : People(name, age) {init {println("Student init, name=$name, age=$age, id=$id")}override fun say() {println("Student say")}
}

         运行程序后,打印如下。

People init, name=li si, age=25
Student init, name=li si, age=25, id=1002
Student say

6.2 覆盖属性

fun main() {var peo : People = Student()peo.doSomething()
}open class People {open var name: String = "zhang san"fun doSomething() {println("doSomething, name=$name")}
}class Student : People() {override var name: String = "li si"
}

        运行程序后,打印如下。

doSomething, name=li si

6.3 类型智能转换

fun main() {var peo: People = Student()// peo.study() // 编译报错if (peo is Student) {peo.study() // 智能转换为Student}
}open class People {
}class Student : People() {fun study() {println("study...")}
}

        说明:Java 没有智能转换特性,需要进行强制类型转换。

7 抽象类

        使用 abstract 修饰的类称为抽象类,抽象类中可以有抽象属性和函数,这些属性和函数被添加了 abstract 修饰符,父类不能实现,子类必须重写实现(子类如果也是抽象类除外)。抽象类不能被实例化,只能实例化其具化子类,抽象类中允许有具化的属性和函数。

fun main() {// var peo = People() // 编译报错, 抽象类不能被实例化var stu = Student()stu.say()
}abstract class People {abstract var name: Stringabstract fun say()
}class Student : People() {override var name: String = "xiao min"override fun say() {println("$name: Hello")}
}

        说明:Java 中只有抽象函数,没有抽象属性。 

        运行程序后,打印如下。

xiao min: Hello

8 接口

        接口与抽象类有些类似,接口里只有抽象属性和函数(函数允许有默认实现,属性不能),Kotlin 中允许一个类实现多个接口,但最多只能继承一个类。

fun main() {var c = C("xxx", "yyy")c.aFun()c.bFun()
}interface A {var x: Stringfun aFun()
}interface B {var y: Stringfun bFun()
}class C(override var x: String, override var y: String) : A, B {override fun aFun() {println("aFun, x=$x")}override fun bFun() {println("bFun, y=$y")}
}

        运行程序后,打印如下。

aFun, x=xxx
bFun, y=yyy

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring AOP常见面试题

目录 一、对于AOP的理解 二、Spring是如何实现AOP的 1、execution表达式 2、annotation 3、基于Spring API,通过xml配置的方式。 4、基于代理实现 三、Spring AOP的实现原理 四、Spring是如何选择使用哪种动态代理 1、Spring Framework 2、Spring Boot 五…

博士推荐 | 纤维与聚合物科学博士,功能性纺织品研发主管

编辑 / 木子 审核 / 朝阳 伟骅英才 伟骅英才致力于以大数据、区块链、AI人工智能等前沿技术打造开放的人力资本生态,用科技解决职业领域问题,提升行业数字化服务水平,提供创新型的产业与人才一体化服务的人力资源解决方案和示范平台&#x…

二分查找【详解】

本期介绍🍖 主要介绍:二分查找的简单思路,为什么必须在有序的前提下才能使用二分查找,该怎么用C程序来实现二分查找,二分查找的局限性👀。 文章目录 1. 题目2. 思路3. 前提条件4. 编写程序 1. 题目 在一个有…

选择性遗忘可以帮助人工智能学得更好?

最近,一些计算机科学家创建了一种更灵活、更灵巧的机器学习模型。诀窍在于:它必须定期忘记它所知道的信息。虽然这种新方法不会取代支撑最大应用程序的庞大模型,但它能揭示这些程序如何理解语言的更多信息。 (PS:如果…

日常007:alias给长命令起个简短的别名

alias 命令可以给那些太长的命令起一个简短的别名。便于记忆,提高输入效率。 用法和示例 1. 创建别名 创建别名,使用语法alias new_commandoriginal_command,例如 alias llls -lF使用别名 $ ll total 32 -rw-r--r-- 1 soulio soulio 1…

【动态规划】代码随想录算法训练营第四十六天 |139.单词拆分,关于多重背包,你该了解这些! ,背包问题总结篇!(待补充)

139.单词拆分 1、题目链接:. - 力扣(LeetCode) 2、文章讲解:代码随想录 3、题目: 给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词…

【Docker】Node 容器部署及配置参数

Node.js环境标准软件基于Bitnami node 构建。当前版本为20.11.1 你可以通过轻云UC部署工具直接安装部署,也可以手动按如下文档操作,该项目已经全面开源,可以从如下环境获取 配置文件地址: https://gitee.com/qingplus/qingcloud-platform Q…

解决报错The following packages have unmet dependencies

一、问题描述 终端输入: nvcc -V 提示: Command nvcc not found, but can be installed with:sudo apt install nvidia-cuda-toolkit按照提示安装,终端输入 sudo apt install nvidia-cuda-toolkit,报错内容如下: …

3分钟彻底搞懂Web UI自动化测试之【POM设计模式】

为什么要用POM设计模式 前期,我们学会了使用PythonSelenium编写Web UI自动化测试线性脚本 线性脚本(以快递100网站登录举例): import time from selenium import webdriver from selenium.webdriver.common.by import By dri…

Python SSH协议库之paramiko使用详解

概要 在网络编程中,远程操作是一项非常常见的需求,特别是在服务器管理和自动化任务执行方面。Python提供了许多库来实现远程操作,其中Paramiko是一个备受欢迎的选择。Paramiko是一个纯Python编写的SSH协议库,它提供了一种简单而强大的方式来执行远程命令、上传和下载文件等…

YUNBEE云贝-热烈祝贺Guo同学成功通过Oracle 19c OCP认证考试!

恭喜Guo同学在 #Oracle19c OCP 考试中取得了OCP证书!该认证是Oracle公司的权威技术标准,适用于有资格为Oracle核心产品提供服务和支持的专业人员。尽管OCP认证考题随着版本变化,并且是全英文考试,对中文习惯的人来说有一定的难度&…

怎样将PPT转成文本格式?PPT文本一键生成文本格式 工作经验分享

在日常工作和学习中,我们经常需要将PPT文件转换为文本格式,以便更好地进行编辑、搜索和分享。下面,我将介绍2种常见的PPT转文本格式的方法,帮助大家轻松实现这一需求。 方法一、使用汇帮PDF转换器软件里的“PPT文件操作”菜单进行…

Git的一些基础命令

使用Git主要涉及以下几个基本步骤和概念。 1. 安装Git 首先,你需要在你的计算机上安装Git。可以从Git的官方网站下载安装程序。 2. 配置Git 安装Git后,需要配置用户信息(用户名和电子邮件地址),因为Git的每次提交都会…

我们做的小工具,爆了!

好消息,好消息,江南皮革。。 开个玩笑,大家好,我是程序员鱼皮。 前段时间我在公众号发文宣传了团队新开发的小工具《代码小抄》,这是一个简单易用的代码分享工具,可以快速、跨设备地自由分享代码。 网址&…

K8S Pod

基本概念 Pod是K8S中非常重要的概念之一,是整个K8S架构的基础和核心。Pod是K8S调度的最小单位,是一个不可拆分的独立个体,K8S将多个业务上相关联的容器(Docker容器)合并到一起,组合成一个Pod,这…

使用Office的小伙伴一定要把这个打开!关键时候能保命

使用电脑办公的小伙伴一定离不开Office。很多小伙伴在使用Office的时候,基本上都是双击打开对应的软件(Word/Excel/Powerpoint)就直接使用。 这种直接打开之后就使用的习惯很不值得提倡。除非你要记录的东西是一分钟就能完成的。 小白在企业上…

php 上传文件报错The file failed to upload

描述:环境lnmp 框架laravel 上传接口调用报错The file failed to upload 一、终端搜索php.ini文件位置 [root90f8687c2388 /]# whereis php.ini php: /usr/bin/php /usr/local/php二、修改文件php.ini配置文件upload_max_filesize项 ; Maximum allowed size for …

在四维轻云中,能够上传哪些地理空间数据?

四维轻云是一款地理空间数据在线管理平台,支持各类地理空间数据的在线管理、浏览及分享,用户可不受时间地点限制,随时随地上传、管理、查看及分享各类地理空间数据。平台具有项目管理、场景搭建、素材库等功能模块,支持在线协作管…

《JAVA与模式》之合成模式

系列文章目录 文章目录 系列文章目录前言一、合成模式二、安全式合成模式的结构三、透明式合成模式的结构四、两种实现方法的选择前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享…

DNS欺骗攻击技术详解及实战代码解析

简介 ARP(Address Resolution Protocol)欺骗和DNS(Domain Name System)欺骗是两种常见的网络攻击手段。本文将通过一段Python代码,详细解析如何利用Scapy库实现ARP欺骗与DNS欺骗,并进行实际操作。 实现原…