Scala的类和对象

1. 初识类和对象

Scala 的类与 Java 的类具有非常多的相似性,示例如下:

// 1. 在 scala 中,类不需要用 public 声明,所有的类都具有公共的可见性
class Person {// 2. 声明私有变量,用 var 修饰的变量默认拥有 getter/setter 属性private var age = 0// 3.如果声明的变量不需要进行初始赋值,此时 Scala 就无法进行类型推断,所以需要显式指明类型private var name: String = _// 4. 定义方法,应指明传参类型。返回值类型不是必须的,Scala 可以自动推断出来,但是为了方便调用者,建议指明def growUp(step: Int): Unit = {
    age += step}// 5.对于改值器方法 (即改变对象状态的方法),即使不需要传入参数,也建议在声明中包含 ()def growUpFix(): Unit = {
    age += 10}// 6.对于取值器方法 (即不会改变对象状态的方法),不必在声明中包含 ()def currentAge: Int = {
    age}/**
   * 7.不建议使用 return 关键字,默认方法中最后一行代码的计算结果为返回值
   *   如果方法很简短,甚至可以写在同一行中
   */def getName: String = name}// 伴生对象
object Person {def main(args: Array[String]): Unit = {// 8.创建类的实例val counter = new Person()// 9.用 var 修饰的变量默认拥有 getter/setter 属性,可以直接对其进行赋值
    counter.age = 12
    counter.growUp(8)
    counter.growUpFix()// 10.用 var 修饰的变量默认拥有 getter/setter 属性,可以直接对其进行取值,输出: 30
    println(counter.age)// 输出: 30
    println(counter.currentAge)// 输出: null
    println(counter.getName)}
}

2. 类

2.1 成员变量可见性

Scala 中成员变量的可见性默认都是 public,如果想要保证其不被外部干扰,可以声明为 private,并通过 getter 和 setter 方法进行访问。

2.2 getter和setter属性

getter 和 setter 属性与声明变量时使用的关键字有关:

使用 var 关键字:变量同时拥有 getter 和 setter 属性;

使用 val 关键字:变量只拥有 getter 属性;

使用 private[this]:变量既没有 getter 属性、也没有 setter 属性,只能通过内部的方法访问;

需要特别说明的是:假设变量名为 age,则其对应的 get 和 set 的方法名分别叫做 ` age` 和 `age_=`。

class Person {private val name = "heibaiying"private var age = 12private[this] var birthday = "2019-08-08"// birthday 只能被内部方法所访问def getBirthday: String = birthday
}object Person {def main(args: Array[String]): Unit = {val person = new Person
    person.age = 30
    println(person.name)
    println(person.age)
    println(person.getBirthday)}
}

示例代码中 `person.age=30` 在执行时内部实际是调用了方法 `person.age_=(30) `,而 `person.age` 内部执行时实际是调用了 `person.age()` 方法。想要证明这一点,可以对代码进行反编译。同时为了说明成员变量可见性的问题,我们对下面这段代码进行反编译:

class Person {
var name = ""
private var age = ""
}

依次执行下面编译命令:

scalac Person.scala
javap -private Person

编译结果如下,从编译结果可以看到实际的 get 和 set 的方法名 (因为 JVM 不允许在方法名中出现=,所以它被翻译成$eq),同时也验证了成员变量默认的可见性为 public。

Compiled from "Person.scala"
public class Person {
private java.lang.String name;
private java.lang.String age;public java.lang.String name();
public void name_$eq(java.lang.String);private java.lang.String age();
private void age_$eq(java.lang.String);public Person();
}

2.3 @BeanProperty

在上面的例子中可以看到我们是使用 `.` 来对成员变量进行访问的,如果想要额外生成和 Java 中一样的 getXXX 和 setXXX 方法,则需要使用@BeanProperty 进行注解。

class Person {@BeanProperty var name = ""
}object Person {def main(args: Array[String]): Unit = {val person = new Person
    person.setName("heibaiying")
    println(person.getName)}
}

2.4 主构造器

和 Java 不同的是,Scala 类的主构造器直接写在类名后面,但注意以下两点

主构造器传入的参数默认就是 val 类型的,即不可变,你没有办法在内部改变传参;

写在主构造器中的代码块会在类初始化的时候被执行,功能类似于 Java 的静态代码块 `static{}`

class Person(val name: String, val age: Int) {  println("功能类似于 Java 的静态代码块 static{}")def getDetail: String = {//name="heibai" 无法通过编译
    name + ":" + age}
}object Person {def main(args: Array[String]): Unit = {val person = new Person("heibaiying", 20)
    println(person.getDetail)}
}输出:
功能类似于 Java 的静态代码块 static{}
heibaiying:20

2.5 辅助构造器

辅助构造器有两点硬性要求:

辅助构造器的名称必须为 this;

每个辅助构造器必须以主构造器或其他的辅助构造器的调用开始。

class Person(val name: String, val age: Int) {private var birthday = ""// 1.辅助构造器的名称必须为 thisdef this(name: String, age: Int, birthday: String) {// 2.每个辅助构造器必须以主构造器或其他的辅助构造器的调用开始this(name, age)this.birthday = birthday}// 3.重写 toString 方法override def toString: String = name + ":" + age + ":" + birthday
}object Person {def main(args: Array[String]): Unit = {
    println(new Person("heibaiying", 20, "2019-02-21"))}
}

2.6 方法传参不可变

在 Scala 中,方法传参默认是 val 类型,即不可变,这意味着你在方法体内部不能改变传入的参数。这和 Scala 的设计理念有关,Scala 遵循函数式编程理念,强调方法不应该有副作用。

class Person() {def low(word: String): String = {
    word="word" // 编译无法通过
    word.toLowerCase}
}

3. 对象

Scala 中的 object(对象) 主要有以下几个作用:

因为 object 中的变量和方法都是静态的,所以可以用于存放工具类;

可以作为单例对象的容器;

可以作为类的伴生对象;

可以拓展类或特质;

可以拓展 Enumeration 来实现枚举。

3.1 工具类&单例&全局静态常量&拓展特质

这里我们创建一个对象 `Utils`,代码如下:

object Utils {/*
   *1. 相当于 Java 中的静态代码块 static,会在对象初始化时候被执行
   *   这种方式实现的单例模式是饿汉式单例,即无论你的单例对象是否被用到,
   *   都在一开始被初始化完成
   */val person = new Person// 2. 全局固定常量 等价于 Java 的 public static final val CONSTANT = "固定常量"// 3. 全局静态方法def low(word: String): String = {
    word.toLowerCase}
}

其中 Person 类代码如下:

class Person() {
  println("Person 默认构造器被调用")
}

新建测试类:

// 1.ScalaApp 对象扩展自 trait App
object ScalaApp extends App {// 2.验证单例
  println(Utils.person == Utils.person)// 3.获取全局常量
  println(Utils.CONSTANT)// 4.调用工具类
  println(Utils.low("ABCDEFG"))}// 输出如下:
Person 默认构造器被调用
true
固定常量
abcdefg

3.2 伴生对象

在 Java 中,你通常会用到既有实例方法又有静态方法的类,在 Scala 中,可以通过类和与类同名的伴生对象来实现。类和伴生对象必须存在与同一个文件中。

class Person() {private val name = "HEIBAIYING"def getName: String = {// 调用伴生对象的方法和属性
    Person.toLow(Person.PREFIX + name)}
}// 伴生对象
object Person {val PREFIX = "prefix-"def toLow(word: String): String = {
    word.toLowerCase}def main(args: Array[String]): Unit = {val person = new Person// 输出 prefix-heibaiying  
    println(person.getName)}
}

3.3 实现枚举类

Scala 中没有直接提供枚举类,需要通过扩展 `Enumeration`,并调用其中的 Value 方法对所有枚举值进行初始化来实现。

object Color extends Enumeration {// 1.类型别名,建议声明,在 import 时有用type Color = Value// 2.调用 Value 方法val GREEN = Value// 3.只传入 idval RED = Value(3)// 4.只传入值val BULE = Value("blue")// 5.传入 id 和值val YELLOW = Value(5, "yellow")// 6. 不传入 id 时,id 为上一个声明变量的 id+1,值默认和变量名相同val PINK = Value}

使用枚举类:

// 1.使用类型别名导入枚举类
import com.heibaiying.Color.Colorobject ScalaApp extends App {// 2.使用枚举类型,这种情况下需要导入枚举类def printColor(color: Color): Unit = {
    println(color.toString)}// 3.判断传入值和枚举值是否相等
  println(Color.YELLOW.toString == "yellow")// 4.遍历枚举类和值for (<- Color.values) println(c.id + ":" + c.toString)
}//输出
true
0:GREEN
3:RED
4:blue
5:yellow
6:PINK

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

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

相关文章

Ps:PSDT 模板文件

自 Photoshop CC 2015.5 版以后&#xff0c;Ps 中新增了一种文件格式&#xff1a;.PSDT。 说明&#xff1a; PSD、PDD、PSDT 都是 Ps 的专用文件格式&#xff0c;需要继续在 Ps 中进行编辑的文件可存为此类格式。 PSD Photoshop document Photoshop 默认文档格式&#xff0c;支…

选择适合你的办公桌:提高工作效率的关键

​在如今的数字时代&#xff0c;越来越多的人将办公桌移到家里或办公室。但是&#xff0c;如何选择适合你的办公桌可能是个挑战。不同的工作需要和工作空间大小会影响你的选择。下面是一些简单的建议&#xff0c;帮助你找到适合你的办公桌&#xff0c;提高工作效率。 首先&…

使用pytorch处理自己的数据集

目录 1 返回本地文件中的数据集 2 根据当前已有的数据集创建每一个样本数据对应的标签 3 tensorboard的使用 4 transforms处理数据 tranfroms.Totensor的使用 transforms.Normalize的使用 transforms.Resize的使用 transforms.Compose使用 5 dataset_transforms使用 1 返回本地…

Android 基于 J2V8 运行 JavasScript 实践

V8 引擎是由 Google 开源的 JavaScript 引擎&#xff0c;Chrome 就是基于 V8 开发&#xff0c;V8 是跨平台的&#xff0c;J2V8 基于 V8 进行开发&#xff0c;使得 js 代码能够在 Android 平台上脱离 WebView 运行。目前&#xff0c;也有很多关于 Android J2V8 的文章&#xff0…

java int char string互相转换和判断

java int 转 ascii码 数字-> ascii码 System.out.println(7 0);ascii码-> 数字 System.out.println(9 - 0);char ch 5; ch (char)(ch -0); //实际计算时是默认将char类型的ch转换为int类型98; 然后将 97 强转为 a System.out.println(ch); // 5 System.out.println…

@RunWith(SpringRunner.class)注解的作用

通俗点&#xff1a; RunWith(SpringRunner.class)的作用表明Test测试类要使用注入的类&#xff0c;比如Autowired注入的类&#xff0c;有了RunWith(SpringRunner.class)这些类才能实例化到spring容器中&#xff0c;自动注入才能生效 官方点&#xff1a; RunWith 注解是JUnit测…

【数据结构】深入浅出理解快速排序背后的原理 以及 版本优化【万字详解】(C语言实现)

快速排序 快速排序递归实现前言一、Hoare版本&#xff08;一&#xff09;算法运行图例&#xff08;二&#xff09;算法核心思路&#xff08;三&#xff09;算法实现步骤&#xff08;1&#xff09;单趟&#xff08;2&#xff09;多趟 &#xff08;四&#xff09;码源详解 递归实…

npm install报 ERESOLVE unable to resolve dependency tree

三四年前的一个项目&#xff0c;打开&#xff0c;npm install 一下&#xff0c;结果报 ERESOLVE unable to resolve dependency tree。 以前install都一切顺利&#xff0c;现在就不行&#xff0c;那很大的可能是npm的版本不同。 PS D:\workSpace\code\*-admin-ui-master> n…

LeetCode热题100——滑动窗口

滑动窗口 1. 无重复字符的最长序列2. 找对字符中所有字母的异位词 1. 无重复字符的最长序列 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 // 题解&#xff1a;利用set集合查询滑窗内是否存在重复字符 int lengthOfLongestSubstring(string…

单元测试反射注解

单元测试 就是针对最小的功能单元(方法)&#xff0c;编写测试代码对其进行正确性测试。 咱们之前是如何进行单元测试的&#xff1f;有啥问题 &#xff1f; Junit单元测试框架 可以用来对方法进行测试&#xff0c;它是由Junit公司开源出来的 具体步骤 Junit框架的常见注解…

『亚马逊云科技产品测评』活动征文|占了个便宜,12个月的免费云服务器

授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 Developer Centre, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 在群里看到有小伙伴说亚马逊可以免费试用服务器&#xff0c;这种好事不得…

Jenkins自动化部署简单配置

下载安装jenkins 安装Jenkins步骤 点击Next的时候会有jdk版本跟Jenkins版本不符合的情况 1. 看下任务管理器内Jenkins服务是否启动&#xff0c;在浏览器里面输入localhost:2023&#xff08;端口号是安装时输入的&#xff09; 2. 根据路径找到放置密码的文件&#xff08;C…

JS冒泡排序(介绍如何执行)

想必大家都多多少少了解过一点排序&#xff0c;让我为大家介绍一下冒泡排序吧&#xff01; 假设我们现在有一个数组[2&#xff0c;4&#xff0c;3&#xff0c;5&#xff0c;1] 我们来分析一下&#xff1a; 1.一共需要的趟数 我们用外层for循环 5个数据我们一共需要走4躺 长度就…

用golang实现一个基于interface的多态示例,展示其使用场景和优劣性。

以下是一个简单的基于interface的多态示例&#xff0c;该示例展示了如何通过使用interface来实现多个不同类型的结构体的共同行为。具体示例如下&#xff1a; package mainimport "fmt"type Animal interface {Speak() string }type Dog struct {Name string }func …

ngixn的指令

Nginx是一个高性能的HTTP和反向代理服务器&#xff0c;它可以处理静态资源、动态内容、负载均衡、反向代理和HTTP缓存等任务。本文将详细介绍在CentOS上安装和配置Nginx服务器&#xff0c;并讲解Nginx常用指令。 安装Nginx 在CentOS上安装Nginx非常简单&#xff0c;只需要执行…

Yolov8改进CoTAttention注意力机制,效果秒杀CBAM、SE

1.CoTAttention 论文地址&#xff1a;2107.12292.pdf (arxiv.org) CoTAttention网络是一种用于多模态场景下的视觉问答&#xff08;Visual Question Answering&#xff0c;VQA&#xff09;任务的神经网络模型。它是在经典的注意力机制&#xff08;Attention Mechanism&#xf…

自动化测试中验证码问题如何解决?

经常会被问到如何解决验证码的问题&#xff0c;在此记录一下我所知道的几种方式。 对于web应用来说&#xff0c;大部分的系统在用户登录时都要求用户输入验证码&#xff0c;验证码的类型的很多&#xff0c;有字母数字的&#xff0c;有汉字的&#xff0c;甚至还要用户输入一条算…

让SOME/IP运转起来——SOME/IP系统设计(上)

什么是SOME/IP&#xff1f; SOME/IP&#xff08;Scalable service-Oriented MiddlewarE over IP&#xff09;是AUTOSAR应用层的协议&#xff0c;是基于IP协议的面向服务的可拓展性的中间件。 SOME/IP中主要定义了&#xff1a; 数据的序列化&#xff1a;SOME/IP支持的数据类型…

Web开发介绍详细介绍

Web开发介绍 1 什么是web开发 Web&#xff1a;全球广域网&#xff0c;也称为万维网(www World Wide Web)&#xff0c;能够通过浏览器访问的网站。 所以Web开发说白了&#xff0c;就是开发网站的&#xff0c;例如下图所示的网站&#xff1a;淘宝&#xff0c;京东等等 那么我们…

SpringBoot集成JPA实现分页和CRUD

SpringBoot集成JPA实现分页和CRUD 文章目录 SpringBoot集成JPA实现分页和CRUDpom.xmlapplication.propertiesaddCategory.jspeditCategory.jsphello.jsplistCategory.jspCategoryCategoryDAOCategoryServiceCategoryServiceImplPage4NavigatorRedisConfigCategoryControllerHel…