Kotlin 类和属性(五)

导读大纲

    • 1.1 封装行为和数据: 类和属性
      • 1.1.1 将数据与类关联并使其可被访问: 属性
      • 1.1.2 计算属性,而不是存储其值: 自定义访问器
      • 1.1.3 Kotlin 源代码目录和包

1.1 封装行为和数据: 类和属性

  1. 与其他面向对象编程语言一样,Kotlin 也提供类的抽象
    • Kotlin 在这方面的概念您一定不会陌生,但会发现与其他面向对象编程语言相比
      1. Kotlin 可以用更少的代码完成许多常见任务
    • <1> Person类—简单的普通 Java 对象(plain old Java object–POJO)
      1. 到目前为止只包含一个属性: name
public class Person {                          // <1>private final String name;                 // <1>public Person(String name) {this.name = name;}public String getName() {return name;}
}
  1. 在 Java 中,这需要一些相当冗长的代码

    • 构造函数的主体完全是重复
      1. 因为它只是将参数赋值给具有相应名称的字段
    • 按照惯例,要访问name字段,Person 类还应提供一个 getter 函数
      1. 即getName, 该函数也只是返回字段的内容
    • 这种重复在 Java 中经常发生
      1. 在 Kotlin 中,这种逻辑的表达不需要这么多模板
  2. 在导读部分中,我们介绍 Java-to-Kotlin 转换器:

    • 这是一种能自动将 Java 代码替换为做相同事情的 Kotlin 代码的工具
    • 让我们来看看转换器的实际操作,将 Person 类转换为 Kotlin 代码
      1. 直接将上述Java代码拷贝并粘贴到Kotlin源文件中
    • <1> Kotlin 提供一种简洁的语法来声明类
      1. 尤其是只包含数据而不包含代码的类
class Person(val name : String)               // <1>
  1. 请注意,修饰符 public 在从 Java 转换到 Kotlin 的过程中消失
    • 在 Kotlin 中,public 是默认的,因此可以省略

1.1.1 将数据与类关联并使其可被访问: 属性

  1. 类的概念将数据和处理这些数据的代码封装成一个实体

    • 在 Java 中,数据存储在字段中,这些字段通常是私有
    • 如果需要让类的客户端访问这些数据
      1. 需要提供访问方法(accessor methods):一个getter和一个setter
    • setter还可以包含验证传递值发送更改通知等附加逻辑
  2. 在 Java 中,字段及其访问器(accessors)的组合通常被称为属性

    • 在 Kotlin 中,属性是一等语言特性,完全取代fields和accessor方法
    • 在类中声明属性的方式与声明变量的方式相同: 使用 val 和 var 关键字
      1. 声明为 val 的属性是只读的,而 var 属性是可变的,可以更改
    • <1> 例如, Person 类已包含一个只读的 name 属性
      1. 可以用一个可变的 isStudent 属性来扩展该类
    • <2> 只读属性–生成一个field和一个getter
    • <3> 可写属性–field、getter 和 setter
    • 基本上,当你声明一个属性时,你就声明相应的访问器(accessors)
      1. 对于只读属性一个 getter
      2. 对于可写属性一个 getter 和一个 setter
class Person(                             // <1>val name: String,                     // <2>var isStudent: Boolean                // <3>
)
  1. 默认情况下,这些访问器的实现非常简单

    • 创建一个字段来存储值,getter 返回该字段值,setter 更新其值
    • 但如果需要,可以声明一个自定义访问器
      1. 使用不同的逻辑计算或更新属性值
    • 上述简洁的 Person 类声明隐藏与原始 Java 代码相同的底层实现
      1. 这是一个带有私有字段的类,在构造函数中初始化
        • 并可通过相应的 getter 访问
    • 这意味着可以在 Java 和 Kotlin 中 以相同的方式使用这个类
      1. 无需考虑它是在哪里声明的, 使用方法看起来完全相同
  2. 下面是如何在 Java 代码中使用 Kotlin 的 Person 类

    • 创建一个名为 Bob 且是学生的的新 Person
    • 请注意, Person 在 Java 和 Kotlin 中的定义看起来是一样
      1. Kotlin 的 name 属性作为名为 getName 的 getter 方法暴露给 Java
    • getter 和 setter 的命名规则有一个例外:
      1. 如果属性名以 is 开头, getter 将不添加额外的前缀
        • 在 setter 名称中,is 将被 set 代替
    • <1> 在Java中调用 isStudent() 和 setStudent() 来访问isStudent属性
public class Demo {public static void main(String[] args) {Person person = new Person("Bob", true);System.out.println(person.getName());// BobSystem.out.println(person.isStudent());       // <1>// trueperson.setStudent(false);                     // <1>// Graduation!System.out.println(person.isStudent());       // <1>// false}
}
// =========================================
Bob
true
false
  1. 将上述Java调用转换为Kotlin代码
    • <1> 调用构造函数时不使用 new 关键字
    • <2> 直接访问属性,但会调用 getter
      1. 现在,你不再显式调用 getter,而是直接引用属性
      2. 逻辑保持不变,但代码更加简洁
    • <3> 直接赋值,但会调用 setter
      1. 在 Java 中,可以使用 person.setStudent(false) 来表示毕业
      2. 而在 Kotlin 中,可以直接对属性进行赋值:person.isStudent=false
object Demo {@JvmStaticfun main(args: Array<String>) {val person = Person("Bob", true)   // <1>println(person.name)               // <2>// Bobprintln(person.isStudent)          // <2>// trueperson.isStudent = false           // <3>// Graduation!println(person.isStudent)// false}
}
  1. 您也可以对 Java 中定义的类使用 Kotlin 属性语法
    • 在 Kotlin 中, Java类中的Getters作为 val 属性访问
      1. 而getter-setter对可作为 var 属性访问
    • 例如,如果一个 Java 类定义名为 getName 和 setName 的方法
      1. 可以将其作为名为 name 的属性进行访问
    • 如果该类定义 isStudent 和 setStudent 方法
      1. 对应的 Kotlin 属性名称是 isStudent
class Person2 {private final String name;private Boolean isStudent;public Person2(String name, Boolean isStudent){this.name = name;this.isStudent = isStudent;}public String getName() {return name;}public Boolean isStudent() {return isStudent;}public void setStudent(Boolean isStudent) {this.isStudent = isStudent;}
}
==========================================
val person2 = Person2("Bob2", true)
println(person2.name)
// Bob
println(person2.isStudent)
// true
person2.isStudent = false
// Graduation!
println(person2.isStudent)
// false
  1. 在大多数情况下,属性会有一个相应的备选字段用来存储属性值
    • 如果属性值需要即时计算(例如,通过从其他属性派生)
      1. 您可以使用自定义 getter 来表达

1.1.2 计算属性,而不是存储其值: 自定义访问器

  1. 一种常见的情况是,属性是对象中其他属性的直接结果
    • 如果您有一个存储宽度和高度的Rectangle类
      1. 可以提供一个当宽度和高度相等时为 true 的isSquare属性
    • 由于这是一个属性,因此可以"随用随查",在访问时进行计算
      1. 无需将该信息存储为一个单独的字段
    • <1> 相反,您可以提供一个自定义的getter
      1. 每次访问该属性都会计算矩形的"方形度"
    • <2> 不必使用带大括号的完整语法,即使用表达式体语法定义getter
      1. 表达式体语法还允许省略属性类型由编译器为你推断类型
      2. 表达式体函数–传送门
    • <3> 无论您选择哪种语法,调用 isSquare 保持不变
class Rectangle(val height: Int, val width: Int){val isSquare: Boolean                 // <1>get() {                           // <1>return height == width}
}
================================== <2>
class Rectangle(val height: Int, val width: Int){val isSquareget() = height == width          // <2>
}
========================================== 
fun main() {val rectangle = Rectangle(41, 43)println(rectangle.isSquare)         // <3>// false
}
  1. 如果需要从 Java 访问该属性,则需要以前一样调用 isSquare 方法
    • 您可能会问,是用自定义 getter 声明一个属性好
      1. 还是在类中定义一个函数(在Kotlin中称为成员函数或方法)好
    • 这两种方法差不多:在实现或性能上没有区别,它们的区别只在于可读性
      1. 一般来说,如果要描述一个类的特性,应将其声明为属性
      2. 如果要描述类的行为,则应选择成员函数

1.1.3 Kotlin 源代码目录和包

  1. 随着程序越来越复杂,由越来越多的函数、类和其他语言结构组成

    • 不可避免地需要开始考虑如何组织源代码
      1. 以便保持项目的可维护性和可浏览性
    • 让我们来看看 Kotlin 项目通常是如何组织的
  2. Kotlin 使用包的概念来组织类(类似于您熟悉的 Java)

    • 每个 Kotlin 文件的开头都可以有一个包语句
      1. 文件中定义的所有声明(类、函数和属性)都将放在该包
    • <1> 下表显示一个源文件示例,其中显示包声明语句的语法
      1. 如果在同一软件包中,可以直接使用其他文件中定义的声明
      2. 如果在不同软件包中,则需要导入
        • 这需要在包声明的下方使用"import"关键字来导入所需的包
package geometry.shapes                                  // <1>
class Rectangle(val height: Int, val width: Int) {val isSquare: Booleanget() = height == width
}
fun createUnitSquare(): Rectangle {return Rectangle(1, 1)
}
  1. Kotlin 并不区分导入类还是导入函数
    • 它允许使用 import 关键字导入任何类型的声明
      1. 但是不允许直接导入包, 试图通过包名来访问其下定义的声明
        title
    • <1> 如果您正在使用geometry.examples包编写项目,那么只需通过名称导入
      1. 就可以使用geometry.shapes包中的类Rectangle和函数createUnitSquare
package geometry.examples                   // <1>
import geometry.shapes.Rectangle            // <1>
import geometry.shapes.createUnitSquare     // <1>
fun main() {println(Rectangle(3, 4).isSquare)// falseprintln(createUnitSquare().isSquare)// true
}
  1. 您还可以导入特定包中定义的所有声明,方法是在包名后写".*"

    • 请注意,这种星形导入(也称为通配符导入)使包中定义的所有内容都可见
      1. 不仅包括类,还包括顶层函数和属性
    • 比如使用import geometry.shapes.*代替显式导入可以使代码正确编译
  2. 在 Java 中,您需要将类放入与包结构相匹配的文件和目录结构

    • 例如,如果您有一个名为 shapes 的包,其中包含多个类
      1. 那么您需要将每个类放入一个名称匹配的单独文件
        • 并将这些文件存储在一个名为 shapes 的目录
    • 下面的列表显示geometry包及其子包在 Java 中的组织结构
      1. 假设 createUnitSquare 函数位于名为 RectangleUtil 的单独文件中
        目录层次结构遵循包层次结构
  3. 在 Kotlin 中,您可以将多个类放在同一个文件中,并为该文件选择任意名称

    • Kotlin也没有对源文件在磁盘上的布局施加任何限制
      1. 您可以使用任何目录结构来组织文件
    • 例如,您可以在 shapes.kt 文件中定义包 geometry.shapes 的所有内容
      1. 将该文件放在 geometry 文件夹
      2. 无需创建单独的 shapes 文件夹
        title
  4. 不过,在大多数情况下,按照 Java 的目录布局

    • 根据包结构将源文件组织到目录仍然是一种好的做法
    • 在 Kotlin 与 Java 混合使用的项目中,坚持使用这种结构尤为重要
      1. 因为这样做可以逐步迁移代码,而不会带来任何意外
    • 不过,你也不应该犹豫是否要将多个类放到同一个文件
      1. 尤其是当这些类很小的时候(在 Kotlin 中,它们通常都很小)

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

UE学习篇ContentExample解读-----------Blueprint_Overview

文章目录 总览描述批次阅览1.1 Blueprint- Hello World1.2 Blueprint- Components1.3 Blueprint- Variables1.4 Blueprint- ConstructionScript1.5 Blueprint- Event Graph1.6 Blueprint- Simple Math1.7 Blueprint- Flow Control 概念总结致谢&#xff1a; 总览描述 打开关卡后…

Golang | Leetcode Golang题解之第430题扁平化多级双向链表

题目&#xff1a; 题解&#xff1a; func dfs(node *Node) (last *Node) {cur : nodefor cur ! nil {next : cur.Next// 如果有子节点&#xff0c;那么首先处理子节点if cur.Child ! nil {childLast : dfs(cur.Child)next cur.Next// 将 node 与 child 相连cur.Next cur.Chi…

超越sora,最新文生视频CogVideoX-5b模型分享

CogVideoX-5B是由智谱 AI 开源的一款先进的文本到视频生成模型&#xff0c;它是 CogVideoX 系列中的更大尺寸版本&#xff0c;旨在提供更高质量的视频生成效果。 CogVideoX-5B 采用了 3D 因果变分自编码器&#xff08;3D causal VAE&#xff09;技术&#xff0c;通过在空间和时…

【变化检测】基于Superpoint+Lightglue+TinyCD建筑物(LEVIR-CD)变化检测实战及ONNX推理

后面再详细完善内容吧&#xff0c;先丢代码&#xff01; 1 创建文件与输入文件夹 注意&#xff1a;img中包括A期与B期文件夹&#xff0c;图片名要求一致对应。 1.1 运行代码 新建main.py文件&#xff0c;内容如下&#xff1a; import os import cv2 import time import a…

Kotlin while 和 for 循环(九)

导读大纲 1.1 while 和 for 循环1.1.1 while 循环1.1.2 范围和级数&#xff1a;for循环 1.1 while 和 for 循环 Kotlin 中的迭代与 Java、C# 或其他语言中的迭代非常相似 while 循环与其他语言中的传统形式相同, 只需简单了解一下即可还会发现 for 循环,其写法为 for ( in ) 是…

从0开始的linux(4)——权限

欢迎来到博主的专栏&#xff1a;从0开始的linux 博主ID&#xff1a;代码小豪 文章目录 用户和用户组文件权限更改文件权限目录文件的权限意义普通文件的权限意义 sudo命令 linux具有多用户的任务环境&#xff0c;为了让每个用户保护各自文件数据&#xff08;防止别的用户对其他…

【功能详解】IoTDB 与 ThingsBoard 成功集成!

可视化工具集成1 IoTDB 实现了 ThingsBoard 的无缝集成对接&#xff0c;IoTDB 构建的工业数据存储处理-可视化呈现链路又多了一种可用、易用的工具选择。 我们的代码已贡献到 ThingsBoard 社区&#xff08;待发版&#xff09;&#xff0c;用户手册也已发布&#xff08;可点击下…

Spring Boot框架:蜗牛兼职网实现

第3章 系统分析 3.1 需求分析 蜗牛兼职网主要是为了提高工作人员的工作效率和更方便快捷的满足用户和企业&#xff0c;更好存储所有数据信息及快速方便的检索功能&#xff0c;对系统的各个模块是通过许多今天的发达系统做出合理的分析来确定考虑用户和企业的可操作性&#xff0…

SpringCloud入门(六)Nacos注册中心(下)

一、Nacos环境隔离 Nacos提供了namespace来实现环境隔离功能。 nacos中可以有多个namespace。namespace下可以有group、service等。不同namespace之间相互隔离&#xff0c;例如不同namespace的服务互相不可见。 使用Nacos Namespace 环境隔离 步骤&#xff1a; 1.在Nacos控制…

【AI画图】stable-diffusion-webui学习之一《安装部署》

简介 Stable Diffusion是2022年发布的深度学习文本到图像生成模型&#xff0c;它是一种潜在扩散模型&#xff0c;它由创业公司Stability AI与多个学术研究者和非营利组织合作开发。目前的SD的源代码和模型都已经开源&#xff0c;在Github上由AUTOMATIC1111维护了一个完整的项目…

Python | Leetcode Python题解之第430题扁平化多级双向链表

题目&#xff1a; 题解&#xff1a; class Solution:def flatten(self, head: "Node") -> "Node":def dfs(node: "Node") -> "Node":cur node# 记录链表的最后一个节点last Nonewhile cur:nxt cur.next# 如果有子节点&#…

OpenCV特征检测(9)检测图像中直线的函数HoughLines()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在二值图像中使用标准 Hough 变换查找直线。 该函数实现了用于直线检测的标准 Hough 变换或标准多尺度 Hough 变换算法。详见 http://homepages…

WebLogic系列漏洞

后台弱⼝令GetShell 漏洞描述 通过弱⼝令进⼊后台界⾯ , 上传部署war包 , getshell 影响范围 全版本&#xff08;前提后台存在弱⼝令&#xff09; 环境搭建 cd vulhub/weblogic/weak_password docker-compose up -d 漏洞复现 默认账号密码&#xff1a;weblogic/Oracle123 (单…

哔哩哔哩自动批量删除抽奖动态解析篇(二)

通过前文我们已经获得账户下转发的动态列表&#xff0c;这一节我们要做的就是根据前一节获得的动态列表数据判断抽奖动态是否已开奖。 一、获取抽奖动态开奖状态信息 首先我们按F12健进入网页源代码&#xff0c;然后点开一条抽奖动态的按钮链接&#xff0c;找到API接口。流程…

Leetcode 1041. 困于环中的机器人

1.题目基本信息 1.1.题目描述 在无限的平面上&#xff0c;机器人最初位于 (0, 0) 处&#xff0c;面朝北方。注意: 北方向 是y轴的正方向。 南方向 是y轴的负方向。 东方向 是x轴的正方向。 西方向 是x轴的负方向。 机器人可以接受下列三条指令之一&#xff1a; “G”&…

基于springboot在线学籍管理系统

基于springboot在线学籍管理系统 摘 要 对在线学籍管理的流程进行科学整理、归纳和功能的精简&#xff0c;通过软件工程的研究方法&#xff0c;结合当下流行的互联网技术&#xff0c;最终设计并实现了一个简单、易操作的在线学籍管理系统。内容包括系统的设计思路、系统模块和…

从零开始一个git操作实例,图文并茂

徒弟不懂git怎么用&#xff0c; 于是写了篇文章&#xff0c; 把本地git操作从头写了一遍&#xff0c; 自己去看吧&#xff01; 0、基本概念 •Git是一个免费、开源的、分布式版本控制系统 •它使用一个特殊的叫做仓库的数据库来记录文件的变化 •仓库中的每个文件都有一个…

【网络】TCP协议的简单使用

目录 echo_service server 单进程单线程 多进程 多线程 线程池 client echo_service_code echo_service 还是跟之前UDP一样&#xff0c;我们先通过实际的代码来实现一些小功能&#xff0c;简单的来使用TCP协议进行简单的通信&#xff0c;话不多说&#xff0c;我们先实现…

Redis面试真题总结(四)

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ AOF 持久化&#xff1f; AOF&#xff08;Append Only File&#x…

Selenium4.0实现自动搜索功能

01.Selenium4.0实现搜索功能 1.安装Selenium及查看Selenium版本 pip install selenium pip show seleniumfrom selenium import webdriver from chromedriver_py import binary_path import time from selenium.webdriver.common.by import By from selenium.webdriver.commo…