Scala 之 Case Class

Posted 两仪生道

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala 之 Case Class相关的知识,希望对你有一定的参考价值。

按照以下的方式进行定义两个class
case class CaseClassDemo(name: String)
class ClassDemo(name: String)

打包后,查看jar包,我们会得到以下3个.class文件


反编译成java代码,我们看下 scala class 和scala case class 的不同


初窥scala Class

ClassDemo.class内容

import scala.reflect.ScalaSignature;
@ScalaSignature(    bytes = "\u0006......" // 实际会很长,这个我们省略掉)public class ClassDemo { public ClassDemo(String name) { }}
// 我们发现,正常定义的scala class 和 java 定义的 class 一致// 相当于定义了一个 包含 字符串参数的 , 并且带一个全参构造函数的 java类class xxx(nameString)


CaseClassDemo.class内容

import scala.Function1;import scala.Option;import scala.Product;import scala.Serializable;import scala.Product.class;import scala.collection.Iterator;import scala.reflect.ScalaSignature;import scala.runtime.BoxesRunTime;import scala.runtime.ScalaRunTime.;
@ScalaSignature(    bytes = "\u0006......." // 实际会很长,这个我们省略掉)public class CaseClassDemo implements Product, Serializable { private final String name;
public static Option<String> unapply(CaseClassDemo var0) { return CaseClassDemo$.MODULE$.unapply(var0); }
public static CaseClassDemo apply(String var0) { return CaseClassDemo$.MODULE$.apply(var0); }
public static <A> Function1<String, A> andThen(Function1<CaseClassDemo, A> var0) { return CaseClassDemo$.MODULE$.andThen(var0); }
public static <A> Function1<A, CaseClassDemo> compose(Function1<A, String> var0) { return CaseClassDemo$.MODULE$.compose(var0); }
public String name() { return this.name; }
public CaseClassDemo copy(String name) { return new CaseClassDemo(name); }
public String copy$default$1() { return this.name(); }
public String productPrefix() { return "CaseClassDemo"; }
public int productArity() { return 1; }
public Object productElement(int x$1) { switch(x$1) { case 0: return this.name(); default: throw new IndexOutOfBoundsException(BoxesRunTime.boxToInteger(x$1).toString()); } }
public Iterator<Object> productIterator() { return .MODULE$.typedProductIterator(this); }
public boolean canEqual(Object x$1) { return x$1 instanceof CaseClassDemo; }
public int hashCode() { return .MODULE$._hashCode(this); }
public String toString() { return .MODULE$._toString(this); }
public boolean equals(Object x$1) {        // 实现过长,当前省略 }
public CaseClassDemo(String name) { this.name = name; class.$init$(this); }}


CaseClassDemo$.class内容 —— 定义了一个单例对象

import scala.Option;import scala.Serializable;import scala.Some;import scala.None.;import scala.runtime.AbstractFunction1;
public final class CaseClassDemo$ extends AbstractFunction1<String, CaseClassDemo> implements Serializable { public static final CaseClassDemo$ MODULE$;
static { new CaseClassDemo$(); }
public final String toString() { return "CaseClassDemo"; }
public CaseClassDemo apply(String name) { return new CaseClassDemo(name); }
public Option<String> unapply(CaseClassDemo x$0) { return (Option)(x$0 == null ? .MODULE$ : new Some(x$0.name())); }
private Object readResolve() { return MODULE$; }
private CaseClassDemo$() { MODULE$ = this; }}

发现:

case 关键词开头的 scala class 除了和正常class一样包含的构造函数之外,还有以下不同:

  1.  implement Product, Serializable

  2.  实现了 apply, unapply方法

  3.  实现了 name参数的 getter方法

  4.  实现了copy方法

  5.  实现了hashCode, toString方法

  6. 生成了一个伴生的单例对象


Case Class和Class的不同之处解析


  1. 实现 Product接口

  2. a. 提供了一组 product开头的方法。可以方便的用类似数组的方式调用类的参数。

     public String productPrefix() { return "CaseClassDemo"; }    // 参数数量 public int productArity() { return 1; } // 0-based    // 返回定义顺序为n的参数结果 public Object productElement(int x$1) { switch(x$1) { case 0: return this.name(); default: throw new IndexOutOfBoundsException(BoxesRunTime.boxToInteger(x$1).toString()); } }    // 提供 iterator方法,可以直接遍历所有属性字段 public Iterator<Object> productIterator() {        // 实际是取用的伴生对象的方法     return .MODULE$.typedProductIterator(this); }

    b. 实现了 equals, canEqual方法(Product 继承接口 Equals)。可以比较结构一致而不是引用一致。

        // 类型比较     public boolean canEqual(Object x$1) { return x$1 instanceof CaseClassDemo;    }    // 结构比较而不是引用比较 public boolean equals(Object x$1) { boolean var6;        if (this != x$1) { // 引用一致 label52: { boolean var3;                // 类型符合 if (x$1 instanceof CaseClassDemo) { var3 = true; } else { var3 = false; }
    if (var3) { label35: { label34: { CaseClassDemo var4 = (CaseClassDemo)x$1; String var10000 = this.name(); String var5 = var4.name();                            // 具体参数比较 if (var10000 == null) { if (var5 != null) { break label34; } } else if (!var10000.equals(var5)) { break label34; }
    if (var4.canEqual(this)) { var6 = true; break label35; } }
    var6 = false; }
    if (var6) { break label52; } }
    var6 = false; return var6; } }
    var6 = true; return var6; }    
  3. 实现Serializable接口

    1. 可以直接进行序列化,反序列化计算。比如spark非driver操作都需要进行序列化。

  4. 实现apply, unapply方法

  5. a. 实际调用了其半身对象的 apply, unapply实现

     public static Option<String> unapply(CaseClassDemo var0) {        // 调用了伴生对象中的 unapply实现 return CaseClassDemo$.MODULE$.unapply(var0); }
    public static CaseClassDemo apply(String var0) {        // 调用了伴生对象中额 apply 实现 return CaseClassDemo$.MODULE$.apply(var0); }
  6. 实现了 name参数的 getter方法

  7. a. 例子中实现了name参数的getter方法

    b. 实际上参数的setter, getter方法在case class里都会被实现,区别在于name参数是 immutable的,只有getter方法。

     public String name() { return this.name; }
  8.  实现了copy方法

  9. a. copy方法,用的不多,在参数很多的类定义时,可以定义一些参数比较少的构造函数,然后调用copy方法进行构造。

        // 浅复制,生成了一个新的对象 public CaseClassDemo copy(String name) { return new CaseClassDemo(name); }
    public String copy$default$1() { return this.name(); }
  10.  实现了hashCode, toString方法

  11. a. 同样调用伴生对象的 hashCode, 以及 toString方法

     public int hashCode() { return .MODULE$._hashCode(this); }
    public String toString() { return .MODULE$._toString(this); }
  12. 生成了一个伴生的单例对象

    1. 包含一个实例 MODULE$

    2. apply方法,返回新对象

    3. unapply方法,进行拆包

    4. readResolve方法,保证单例对象 


case class的用途

  1.  模式匹配 scala match

    1. 依赖unapply方法,可以直接匹配到类中的参数

  2. 短写方式构建新实例

    1. 依赖apply方法,不使用new 关键字构建新的对象

  3. 直接参与序列化操作

    1. case class的定义及其伴生的单例都是实现序列化接口的

  4. 像数组一下调用参数

    1. 我们知道的 Tuple1~Tuple22 都是特殊的 Product实现,实现Product后相当于在 spark计算中拿到了通行证,参与各种高级的计算, 比如隐式转换,DataFrame, Dataset中的方法等。

  5. getter和setter方法

  6. 直接进行结构比较,而不是引用比较

    1. 在大规模数据处理比较中特别重要



扩展知识点:

1. trait:  scala.Product extends Any with Equals


以上是关于Scala 之 Case Class的主要内容,如果未能解决你的问题,请参考以下文章

Scala 中 case class 与 class 的区别(代码示例)

Scala class和case class的区别

Scala class和case class的区别

scala case class

scala-case class

Scala总结之模式匹配