首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Scala 類別操作精要:有理數類別實戰與運算子重載真相

     編輯:Java 相關知識

本文為系列第二篇,聚焦 Scala 類別定義與使用特性。以實作有理數(Rational)類別為主線,展示建構子鏈、不可變設計、運算子方法、隱式轉換與 Java 互通測試等核心技術。

類別定義與主建構子

Scala 類別參數直接置於類別標籤,即為主建構子:


class Rational(n: Int, d: Int) {
  private def gcd(x: Int, y: Int): Int = if (x == 0) y else gcd(y % x, x)
  private val g = gcd(n, d)
  val numer: Int = n / g
  val denom: Int = d / g
  // 運算子方法...
  override def toString = s"Rational: [$numer / $denom]"
}

建構子邏輯直接寫在類別主體,執行順序自上而下。private val g 為建構子期間計算的中介值,外部不可見。

建構子鏈:輔助建構子呼叫主建構子


class Rational(n: Int, d: Int) {
  def this(d: Int) = this(0, d)  // 單參數建構子委派給主建構子
}

所有輔助建構子最終必須委派給主建構子,確保初始化邏輯單一入口。

不可變物件與線程安全

numer、denom 為 val(唯讀),無 setter。操作回傳新實例:


def +(that: Rational) = new Rational(numer * that.denom + that.numer * denom, denom * that.denom)
def -(that: Rational) = new Rational(numer * that.denom - that.numer * denom, denom * that.denom)
def *(that: Rational) = new Rational(numer * that.numer, denom * that.denom)
def /(that: Rational) = new Rational(numer * that.denom, denom * that.numer)

此設計天然線程安全,同 java.lang.String。

運算子即方法:名字有趣的方法

關鍵洞見:Scala 無運算子重載。+、-、*、/ 皆為合法方法名稱。r1 + r2 實為 r1.+(r2) 語法糖。同理可自訂一元運算子:


def unary_~ : Rational = new Rational(denom, numer)  // 求倒數
val r6 = ~r1  // 呼叫 unary_~

unary_ 前綴標識一元運算子(+、-、~、! 四種)。

Scala 編譯器的隱式推論:+= 自動合成

未顯式定義 += 也能用:


var r5 = new Rational(3, 4)
r5 += r1  // 編譯器自動轉為 r5 = r5.+(r1)

任何 op= 皆自動展開為 op 呼叫加賦值。

JVM 視角:javap 反編譯揭秘


public class Rational extends java.lang.Object implements scala.ScalaObject {
  public Rational(int, int);
  public Rational unary_$tilde();      // ~ -> $tilde
  public Rational $plus(Rational);     // + -> $plus
  public Rational $minus(Rational);    // - -> $minus
  public Rational $times(Rational);    // * -> $times
  public Rational $div(Rational);      // / -> $div
  public int numer();
  public int denom();
  ...
}

運算子方法編譯為 $op 形式,因 JVM 方法名允許 $ 但 Java 原始碼不允許。Java 調用需用反射或 Groovy/JRuby。

Java 單元測試 Scala 類別


@Test public void testAddRationals() {
  Rational r1 = new Rational(2, 5);
  Rational r2 = new Rational(1, 3);
  Rational r3 = (Rational) reflectInvoke(r1, "$plus", r2);  // 反射調用 $plus
  assertEquals(11, r3.numer());
  assertEquals(15, r3.denom());
}

既可驗證正確性,又證明 Scala 類別可無縫納入 Java 建置流程。

「更好的 Java」:簡潔 POJO 定義

傳統 Java POJO 需大量 getter/setter:


// Java 版:~30 行
public class JavaPerson { private String firstName; public String getFirstName() {...} public void setFirstName(...) {...} ... }

Scala 版(唯讀,線程安全):


class Person(firstName: String, lastName: String, age: Int) {
  override def toString = s"[Person firstName:$firstName lastName:$lastName age:$age]"
}
// 編譯器自動產生 firstName(), lastName(), age() 存取器

需可變欄位只改 val 為 var,編譯器同步產生 firstName_$eq(String) 修改器:


class Person(var firstName: String, var lastName: String, var age: Int) { ... }

若需 JavaBeans 相容,加註解 @scala.reflect.BeanProperty 即可生成標準 get/set。

結語

Scala 以函數式簡潔性強化物件模型:主建構子、不可變預設、運算子方法統一、隱式推論、Java 互通。可直接用於生成 Spring/Hibernate 所需 POJO。下一篇將進入函數式核心領域。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved