0%

scala类和对象

Scala 类和对象:面向对象的简洁实现

Scala 作为一门纯粹的面向对象语言,其类和对象的设计既保留了面向对象的核心思想,又通过语法糖简化了代码编写,相比 Java 更加简洁灵活。本文将深入解析 Scala 类和对象的定义、属性访问机制及底层实现。

类的定义与特性

基本语法

Scala 中类的定义无需显式声明 public(默认即为公有),一个源文件可包含多个类,所有类均具有公有可见性。

1
2
3
4
// 语法格式
[修饰符] class 类名 {
// 类体(属性、方法等)
}

示例:定义一个简单的类

1
2
3
4
5
6
7
8
class Cat {
// 用var声明可变属性(会生成getter和setter)
var name: String = _ // _表示赋默认值(需指定类型)
var color: String = _

// 用val声明不可变属性(仅生成getter)
val life: Int = 10 // val必须显式赋值,且不可修改
}
代码解析:
  • 属性初始化:Scala 要求类的属性必须显式初始化。若暂时不想赋值,可用 _ 赋默认值(需指定类型),默认值规则与 Java 基本类型一致(如字符串默认 null,整数默认 0)。
  • varval 的区别:
    • var:可变属性,编译后会生成 getter(获取值)和 setter(修改值)方法。
    • val:不可变属性,编译后仅生成 getter 方法(无 setter,因为值不可修改)。

对象的实例化与使用

实例化对象

Scala 实例化对象的语法与 Java 类似,但可省略 new 后的括号(无参构造时)。

1
2
3
4
5
6
7
8
9
10
11
12
13
object CatDemo {
def main(args: Array[String]): Unit = {
// 实例化Cat对象(无参构造可省略括号)
val cat = new Cat() // 或简写为 new Cat

// 访问和修改属性(实际调用getter和setter)
cat.name = "小花" // 调用setter方法
cat.color = "黄白" // 调用setter方法

// 打印属性(实际调用getter方法)
println(s"${cat.name}的颜色是${cat.color},寿命为${cat.life}年")
}
}
输出结果:
1
小花的颜色是黄白,寿命为10年

底层实现:从 Scala 到 Java 的转换

Scala 代码最终会编译为 JVM 字节码,通过反编译可清晰看到类的底层实现。以上述 Cat 类为例,编译后生成的 Java 代码大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class Cat {
// 属性默认是private
private String name;
private String color;
private final int life; // val修饰的属性是final

// 无参构造方法
public Cat() {
this.life = 10; // val属性在构造时初始化
}

// var属性的getter(name())
public String name() {
return this.name;
}

// var属性的setter(name_$eq(),Scala的特殊命名)
public void name_$eq(String x$1) {
this.name = x$1;
}

// color的getter和setter(与name类似)
public String color() {
return this.color;
}
public void color_$eq(String x$1) {
this.color = x$1;
}

// val属性的getter(仅读取,无setter)
public int life() {
return this.life;
}
}

关键发现:

  1. 属性访问的本质
    Scala 中 cat.name = "小花" 并非直接修改私有属性,而是调用了编译器生成的 name_$eq("小花") 方法(setter);cat.name 则调用了 name() 方法(getter)。这种语法糖让代码更简洁。
  2. val 的不可变性
    val life: Int = 10 编译后为 private final int life,且无 setter 方法,确保值无法修改。
  3. 构造方法
    类体中 val life: Int = 10 的初始化逻辑会被放入构造方法中执行。

类的访问修饰符

Scala 支持多种访问修饰符,控制属性和方法的可见性,与 Java 略有差异:

修饰符 含义 对比 Java
无修饰符 同包可见(默认) Java 默认是包内可见
private 仅当前类可见(包括伴生对象) Java 的 private 是类内可见
protected 仅当前类及子类可见(同包子类不可见) Java 的 protected 允许同包访问
private[this] 仅当前实例可见(更严格的 private) 无对应修饰符

示例:使用 private 修饰符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Dog {
private var age: Int = 3 // 仅Dog类及伴生对象可见

def getAge(): Int = age // 类内可访问
}

object Dog {
def printAge(dog: Dog): Unit = {
println(dog.age) // 伴生对象可访问private属性
}
}

// 测试
object DogDemo {
def main(args: Array[String]): Unit = {
val dog = new Dog()
println(dog.getAge()) // 合法:通过方法访问
// println(dog.age) // 错误:外部不可访问private属性
Dog.printAge(dog) // 合法:伴生对象可访问
}
}

与 Java 类的核心差异

特性 Scala Java
源文件与类的关系 一个源文件可包含多个类(均为 public) 一个源文件通常对应一个 public 类
属性默认访问权限 private(通过 getter/setter 访问) 默认是包内可见(直接访问)
构造方法 主构造器与类体融合(后续章节详解) 需显式定义构造方法
伴生对象 允许伴生对象访问类的 private 成员 无伴生对象概念,需用静态内部类模拟
不可变属性 val 修饰(自动生成 final 字段) 需显式用 final 修饰

最佳实践

  1. 优先使用 val:不可变属性(val)更符合函数式编程思想,线程安全且减少副作用。
  2. 合理初始化属性:避免使用 _ 赋默认值(除非必要),显式初始化更清晰。
  3. 利用访问修饰符:通过 privateprotected 控制属性访问,封装内部状态。
  4. 避免过度暴露属性:如需外部访问,优先提供方法而非直接用 var 声明(如 private var age: Int + def getAge() = age)。

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10