scala有关 类 的知识点与Java的比较

发布于:2025-03-07 ⋅ 阅读:(21) ⋅ 点赞:(0)

1. 类的定义:最简形式

Scala 的类定义和 Java 类似,但语法更简洁。

Scala 示例

scala复制代码

class Person {
  var name: String = ""  // 可变变量
  val age: Int = 0       // 不可变变量(类似Java的final)
  
  def sayHello(): Unit = {
    println(s"Hello, I'm $name, $age years old.")
  }
}

Java 对比

java复制代码

public class Person {
    private String name = "";
    private final int age = 0;

    public void sayHello() {
        System.out.println("Hello, I'm " + name + ", " + age + " years old.");
    }
}

关键点

  • Scala 中成员变量(字段)可以直接声明在类体中,不需要放在构造器中。
  • var 表示可变变量,val 表示不可变变量(类似 Java 的 final)。
  • 方法定义用 def,返回值类型在参数后(如 Unit 表示无返回值,类似 Java 的 void)。

2. 构造器:主构造器 vs 辅助构造器

Scala 的构造器分为主构造器辅助构造器,这是与 Java 不同的重要特性。

(1) 主构造器(Primary Constructor)

主构造器是类定义的一部分,直接写在类名后面。

Scala 示例

scala复制代码

class Person(var name: String, val age: Int) {
  def sayHello(): Unit = {
    println(s"Hello, I'm $name, $age years old.")
  }
}

Java 对比

java复制代码

public class Person {
    private String name;
    private final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void sayHello() {
        System.out.println("Hello, I'm " + name + ", " + age + " years old.");
    }
}

关键点

  • 主构造器的参数直接写在类名后的括号中。
  • 如果参数用 var 或 val 修饰,会自动生成对应的公有字段(类似 Java 的 public 成员变量)。
  • 如果参数不加 var/val,则参数仅作为构造器参数使用,不会成为类的字段。

(2) 辅助构造器(Auxiliary Constructor)

辅助构造器通过 def this(...) 定义,且必须调用主构造器。

Scala 示例

scala复制代码

class Person(var name: String, val age: Int) {
  // 辅助构造器1
  def this(name: String) {
    this(name, 0)  // 必须调用主构造器
  }

  // 辅助构造器2
  def this() {
    this("Anonymous")  // 调用辅助构造器1,最终仍调用主构造器
  }
}

Java 对比

java复制代码

public class Person {
    private String name;
    private final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person(String name) {
        this(name, 0);
    }

    public Person() {
        this("Anonymous");
    }
}

关键点

  • 辅助构造器必须首先调用主构造器(或另一个辅助构造器)。
  • 主构造器是 Scala 类的唯一入口。

3. 继承:extends 关键字

Scala 的继承机制与 Java 类似,但方法覆盖必须用 override 关键字。

Scala 示例

scala复制代码

class Animal {
  def speak(): Unit = {
    println("Animal speaks")
  }
}

class Dog extends Animal {
  override def speak(): Unit = {
    println("Dog barks")
  }
}

Java 对比

java复制代码

public class Animal {
    public void speak() {
        System.out.println("Animal speaks");
    }
}

public class Dog extends Animal {
    @Override
    public void speak() {
        System.out.println("Dog barks");
    }
}

关键点

  • 用 extends 继承父类。
  • 覆盖方法必须加 override 关键字(Java 的 @Override 是注解,Scala 的 override 是强制语法)。

4. 抽象类:abstract 关键字

抽象类用于定义未实现的方法或字段,类似 Java 的抽象类。

Scala 示例

scala复制代码

abstract class Shape {
  def area(): Double  // 抽象方法(无实现)
  val color: String   // 抽象字段
}

class Circle(radius: Double, override val color: String) extends Shape {
  override def area(): Double = Math.PI * radius * radius
}

Java 对比

java复制代码

public abstract class Shape {
    public abstract double area();
    public abstract String getColor();
}

public class Circle extends Shape {
    private double radius;
    private String color;

    public Circle(double radius, String color) {
        this.radius = radius;
        this.color = color;
    }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }

    @Override
    public String getColor() {
        return color;
    }
}

关键点

  • 抽象方法用 def 定义,无方法体。
  • 抽象字段用 val 或 var 声明,无初始值。
  • 子类必须实现所有抽象成员。

5. 伴生对象:object 关键字

Scala 没有静态成员(static),而是通过伴生对象实现类似功能。

Scala 示例

scala复制代码

class Person(val name: String, val age: Int)

// 伴生对象(与类同名)
object Person {
  def apply(name: String, age: Int): Person = new Person(name, age)
  def apply(name: String): Person = new Person(name, 0)
}

// 使用伴生对象创建实例
val p1 = Person("Alice", 30)  // 调用 apply 方法
val p2 = Person("Bob")

Java 对比

java复制代码

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public static Person create(String name, int age) {
        return new Person(name, age);
    }

    public static Person create(String name) {
        return new Person(name, 0);
    }
}

// 使用静态工厂方法
Person p1 = Person.create("Alice", 30);
Person p2 = Person.create("Bob");

关键点

  • 伴生对象与类同名,定义在同一个文件中。
  • 通过 apply 方法实现类似构造器的调用语法。
  • 伴生对象可以访问类的私有成员。

6. 特质(Trait):类似接口的增强版

Scala 的 trait 类似 Java 的接口,但支持方法实现和多重继承。

Scala 示例

scala复制代码

trait Speaker {
  def speak(): Unit  // 抽象方法
  def greet(): Unit = {
    println("Hello!")  // 具体方法
  }
}

class Human extends Speaker {
  override def speak(): Unit = {
    println("Human speaks")
  }
}

val h = new Human
h.speak()  // 输出:Human speaks
h.greet()  // 输出:Hello!

Java 对比(Java 8+):

java复制代码

public interface Speaker {
    void speak();
    default void greet() {
        System.out.println("Hello!");
    }
}

public class Human implements Speaker {
    @Override
    public void speak() {
        System.out.println("Human speaks");
    }
}

关键点

  • 特质可以包含抽象方法和具体方法。
  • 类通过 with 关键字继承多个特质:

    scala复制代码

    class Robot extends Speaker with Walker with Worker
  • 解决多重继承冲突时,采用线性化规则(最后继承的特质优先级最高)。

7. Case 类:专为模式匹配优化的类

case class 是 Scala 中特殊的类,自动生成常用方法(如 equalshashCodetoString)。

Scala 示例

scala复制代码

case class Point(x: Int, y: Int)

val p1 = Point(1, 2)
val p2 = Point(1, 2)
println(p1 == p2)  // 输出 true(自动实现值比较)

Java 对比
需要手动实现 equalshashCodetoString 等方法。

关键点

  • 默认字段为 val(不可变)。
  • 自动生成伴生对象和 apply 方法。
  • 支持模式匹配:

    scala复制代码

    def describe(p: Point): String = p match {
      case Point(0, 0) => "原点"
      case Point(x, 0) => s"X轴上的点($x, 0)"
      case _ => "其他点"
    }

总结:Scala vs Java 类设计的差异

特性 Scala Java
构造器 主构造器 + 辅助构造器 普通构造器
静态成员 通过伴生对象实现 static 关键字
接口 特质(支持方法实现) 接口(Java 8+ 支持默认方法)
不可变类 用 case class 自动生成 需手动实现
多重继承 通过特质支持 不支持(接口允许多实现)