Scala 之 Case Class
Posted 两仪生道
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala 之 Case 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;
bytes = // 实际会很长,这个我们省略掉
)
public class ClassDemo {
public ClassDemo(String name) {
}
}
// 我们发现,正常定义的scala class 和 java 定义的 class 一致
// 相当于定义了一个 包含 字符串参数的 , 并且带一个全参构造函数的 java类
class xxx(name: String)
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.;
(
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一样包含的构造函数之外,还有以下不同:
implement Product, Serializable
实现了 apply, unapply方法
实现了 name参数的 getter方法
实现了copy方法
实现了hashCode, toString方法
生成了一个伴生的单例对象
Case Class和Class的不同之处解析
实现 Product接口
实现Serializable接口
可以直接进行序列化,反序列化计算。比如spark非driver操作都需要进行序列化。
实现apply, unapply方法
实现了 name参数的 getter方法
实现了copy方法
实现了hashCode, toString方法
生成了一个伴生的单例对象
包含一个实例 MODULE$
apply方法,返回新对象
unapply方法,进行拆包
readResolve方法,保证单例对象
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;
}
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);
}
a. 例子中实现了name参数的getter方法
b. 实际上参数的setter, getter方法在case class里都会被实现,区别在于name参数是 immutable的,只有getter方法。
public String name() {
return this.name;
}
a. copy方法,用的不多,在参数很多的类定义时,可以定义一些参数比较少的构造函数,然后调用copy方法进行构造。
// 浅复制,生成了一个新的对象
public CaseClassDemo copy(String name) {
return new CaseClassDemo(name);
}
public String copy$default$1() {
return this.name();
}
a. 同样调用伴生对象的 hashCode, 以及 toString方法
public int hashCode() {
return .MODULE$._hashCode(this);
}
public String toString() {
return .MODULE$._toString(this);
}
case class的用途
模式匹配 scala match
依赖unapply方法,可以直接匹配到类中的参数
短写方式构建新实例
依赖apply方法,不使用new 关键字构建新的对象
直接参与序列化操作
case class的定义及其伴生的单例都是实现序列化接口的
像数组一下调用参数
我们知道的 Tuple1~Tuple22 都是特殊的 Product实现,实现Product后相当于在 spark计算中拿到了通行证,参与各种高级的计算, 比如隐式转换,DataFrame, Dataset中的方法等。
getter和setter方法
直接进行结构比较,而不是引用比较
在大规模数据处理比较中特别重要
扩展知识点:
1. trait: scala.Product extends Any with Equals
以上是关于Scala 之 Case Class的主要内容,如果未能解决你的问题,请参考以下文章