case class 和class的區別以及構造器參數辨析

来源:https://www.cnblogs.com/PerkinsZhu/archive/2018/07/13/9307460.html
-Advertisement-
Play Games

工作中偶然發現Scala構造方法中的參數,無論是否有val/var修飾都可以順利編譯運行,如下: 那麼兩者的區別在哪裡呢?對於case class呢?其區別又在哪裡?其應用場景又在哪裡呢?下麵就辨析一下如下幾個類的區別 單純的從代碼中來看,發現不了什麼區別,只是簡單的多了一個val的修飾符。為了一探 ...


工作中偶然發現Scala構造方法中的參數,無論是否有val/var修飾都可以順利編譯運行,如下:

1     class AA(name: String)
2     class BB(val name: String)

那麼兩者的區別在哪裡呢?對於case class呢?其區別又在哪裡?其應用場景又在哪裡呢?下麵就辨析一下如下幾個類的區別

 1     class AA(name: String)
 2     class BB(val name: String)
 3     class CC(var name: String)
4 class DD(private val name: String) 5 class EE(private[this] val name: String)
6 case class FF(name: String) 7 case class GG(val name: String) 8 case class HH(var name: String) 9 case class II(private val name: String) 10 case class JJ(private[this] val name: String)

 

 單純的從代碼中來看,發現不了什麼區別,只是簡單的多了一個val的修飾符。為了一探究竟,先對源碼進行編譯,然後通過javap對其class文件進行反編譯,查看其與源碼的區別。

一、普通類構造器中val/var 存在和不存在的區別

源碼:

1     class AA(name: String)
2     class BB(val name: String)
3     class CC(var name: String)

 反編譯結果:

 1 Compiled from "Test.scala"
 2 public class AA {
 3   public AA(java.lang.String);
 4 }
 5 
 6 Compiled from "Test.scala"
 7 public class BB {
 8   private final java.lang.String name;
 9   public java.lang.String name();
10   public BB(java.lang.String);
11 }
12 
13 Compiled from "Test.scala"
14 public class CC {
15   private java.lang.String name;
16   public java.lang.String name();
17   public void name_$eq(java.lang.String);
18   public CC(java.lang.String);
19 }

  結論:構造器中val修飾的參數,編譯之後會在該類中添加一個private final全局常量,同時提供一個用於獲取該常量的public方法,無設置方法。

   構造器中var修飾的參數,編譯之後會在該類中添加一個private全局變數,同時提供兩個獲取和設置該變數值的public方法。

    構造器中無修飾符的參數,則該參數屬於構造函數內的局部參數,僅僅在該構造函數內部訪問

二、普通類構造器中private和private[this] 修飾參數的區別

源碼:

1     class DD(private val name: String)
2     class EE(private[this] val name: String)

 反編譯結果:

Compiled from "Test.scala"
public class DD {
  private final java.lang.String name;
  private java.lang.String name();
  public DD(java.lang.String);
}

Compiled from "Test.scala"
public class EE {
  public EE(java.lang.String);
}

 結論:private 修飾的構造器參數,編譯之後會在該類中添加一個private final的全局常量,同時提供一個private的訪問該參數的方法。即該參數可在該類範圍內訪問

   private[this]修飾的構造器參數,不存在全局變數,只能在該構造方法中訪問,在該類中無法訪問。同 class AA(name: String)

註意:Scala整個類體就是其構造函數,所以,站在Scala角度看,private[this]修飾的構造器參數能夠在整個類中訪問,而站在Java角度看,該參數僅僅能夠在構造函數中訪問,在類中無法訪問。而站在Scala角度看,private[this]和 private的主要區別在於,private[this]修飾的參數無法通過e.name的方式訪問,即使在該類的內部。註意下圖:

圖中,在EE#show中是無法訪問that.name的,即使that的類型本身就是EE也不行的。這才是private[this]和private在Scala中的主要區別。

 三、普通class和case class的區別

源碼:

1   case class FF(name: String)

 編譯之後會發現在文件夾下麵多出兩個class文件,一個為FF.class,另一個為FF$.class文件。對兩個文件進行反編譯

反編譯結果:

 1 Compiled from "Test.scala"
 2 public class FF implements scala.Product,scala.Serializable {
 3     //private final 修飾的name常量
 4     private final java.lang.String name;
 5     //public修飾獲取name的方法,可用於外部訪問
 6     public java.lang.String name();
 7     //public修飾的構造函數
 8     public FF(java.lang.String);
 9     public static scala.Option<java.lang.String> unapply(FF);
10     public static FF apply(java.lang.String);
11     public static <A> scala.Function1<java.lang.String, A> andThen(scala.Function1<FF, A>);
12     public static <A> scala.Function1<A, FF> compose(scala.Function1<A, java.lang.String>);
13     public FF copy(java.lang.String);
14     public java.lang.String copy$default$1();
15     public java.lang.String productPrefix();
16     public int productArity();
17     public java.lang.Object productElement(int);
18     public scala.collection.Iterator<java.lang.Object> productIterator();
19     public boolean canEqual(java.lang.Object);
20     public int hashCode();
21     public java.lang.String toString();
22     public boolean equals(java.lang.Object);
23 }
24 
25 Compiled from "Test.scala"
26 public final class FF$ extends scala.runtime.AbstractFunction1<java.lang.String, FF> implements scala.Serializable {
27     //靜態的FF$對象
28     public static FF$ MODULE$;
29     //構造函數為private
30     private FF$();
31     
32     //返回FF對象的 apply方法
33     public FF apply(java.lang.String);
34     
35     public static {};
36     public final java.lang.String toString();
37     public scala.Option<java.lang.String> unapply(FF);
38     private java.lang.Object readResolve();
39     public java.lang.Object apply(java.lang.Object);
40 }

  分析:

  先看FF.class

   1、對比class AA(name: String)的結果來看,case class 自動實現了scala.Product,scala.Serializable兩個特質(介面),因此,case class類中自然也會實現這兩個特質中的抽象方法/覆寫一些方法(11~22行)。

1 public class AA
2 public class FF implements scala.Product,scala.Serializable 

    2、對比 public class BB,在類內部都具有一個全局常量name和一個獲取該常量的public方法,同時兩者都具有一個public的構造函數。

   3、實現了一些特質中的一些方法,覆寫了Java Object中的一些方法。例如:andThen() toString() hashCode()等

   再看FF$

    1、有一個public  static修飾名為 MODULE$ 的 FF$對象

    2、構造器被私有化,用private修飾。

    3、組合1、 2、兩點可知,FF$是一個單例類。其矢志不渝就是Scala中FF類的伴生對象。 

 結論

  Scala編譯器在對case class進行編譯的時候做了特殊處理,擴展了其方法和功能,加入了scala.Product,scala.Serializable的特性,同時為其提供了該類的伴生對象。另外,對於case class 構造器參數,其預設以public修飾,可允許外部調用

 四、其他

 上面幾個對比理解了,下麵這幾個類之間的區別也就可以舉一反三了。

1     case class GG(val name: String)
2     case class HH(var name: String)
3     case class II(private val name: String)
4     case class JJ(private[this] val name: String)

 

 

 

=========================================

原文鏈接:case class 和class的區別以及構造器參數辨析 轉載請註明出處!

=========================================

-----end


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 使用yarn的優點,簡而言之就是:鎖定版本,下載之前檢查完整性。 輸入 yarn --help 可以獲得幫助 ...
  • 喜歡的朋友可以關註下,粉絲也缺。 自從Spring推出Boot,Cloud系列之後,一度成為熱門的框架,現在大部分的招聘要求都要有相關的開發經驗,藉此我在這裡就給大家分享一下如何玩轉SpringBoot跟Mybatis。 這裡我給大家提供我創建的demo下載地址 https://download.c ...
  • 控制反轉是應用於軟體工程領域中的,在運行時被裝配器對象來綁定耦合對象的一種編程技巧,對象之間耦合關係在編譯時通常是未知的。在傳統編程方式中,業務邏輯的流程是應用程式中早已被設定好關聯關係的對象來決定的。在使用控制反轉的情況下,業務邏輯的流程是由對象關係圖來決定的,該對象關係圖有裝配器負責實例化,這種 ...
  • 在大容量,高負荷的web系統中,對資料庫進行一系列拆分,可有效提升資料庫容量和性能。在初學程式的早期,程式員通常都喜歡按傳統資料庫設計模式,設計為單庫和單一功能表的結構,這樣的結構在數據量和併發量達到一定程度之後,會出現嚴重性能問題和維護問題。在出現問題的時候才著手進行優化,會非常痛苦,所以應該在系 ...
  • List、Set、數據結構、Collections 初次學習,涉及到List集合,Set集合和數據結構方面的一些知識,有錯誤還請批評指正 數據結構 數據存儲的常用結構有:棧、隊列、數組、鏈表和紅黑樹。 棧 先進後出(FILO). 隊列 先進先出(FIFO). 數組 有序的元素序列,以索引訪問.查詢快 ...
  • datetime是模塊,datetime模塊還包含一個datetime類,通過from datetime import datetime導入的才是datetime這個類。 strptime(): 用戶輸入的日期和時間是字元串,要處理日期和時間,首先必須把str轉換為datetime。轉換方法是通過d ...
  • 本文主要記錄了SpringBoot中AOP註解式攔截與方法規則攔截的基本使用。 ...
  • 本文內容: servlet的介紹 servlet的基礎使用介紹 HttpServlet ServletConfig ServletContext Cookie Session 數據域對象 servlet的介紹: Servlet是sun公司提供的一門用於開發動態web資源的技術。 servlet程式運... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...