开发者社区> boxti> 正文

话说模式匹配(6) case类的细节

简介:
+关注继续查看

我们在第二篇文章里曾提到过:

本质上case class是个语法糖,对你的类构造参数增加了getter访问,还有toString, hashCode, equals 等方法; 最重要的是帮你实现了一个伴生对象,这个伴生对象里定义了apply方法和unapply方法。

现在我们来详细的分析一下case class,对一个简单的样本类

case class B()

反编译后看到编译器自动给它混入了Product特质,以及Serializable特质:

public class B implements scala.Product,scala.Serializable {
 public B copy();
 public java.lang.String productPrefix();
 public int productArity();
 public java.lang.Object productElement(int);
 public scala.collection.Iterator<java.lang.Object> productIterator();
 public boolean canEqual(java.lang.Object);
 public int hashCode();
 public java.lang.String toString();
 public boolean equals(java.lang.Object);
 public B();
}

再看看它的半生对象:

//伴生对象也混入了AbstractFunction0 和 Serializable 特质
public final class B$ extends scala.runtime.AbstractFunction0<B> implements scala.Serializable {
 public static final B$ MODULE$;
 public static {};
 public final java.lang.String toString();
 public B apply();
 public boolean unapply(B);
 public java.lang.Object apply();
}

通过反编译的结果我们了解到了几点:

  1. 编译器对case类混入了Product特质
  2. 编译器对case类增加了copy方法;
  3. 编译器对case类实现了equals/hashCode/toString等方法
  4. 伴生对象中最重要的方法是 unapply 这个方法是在进行构造器模式匹配时的关键。
  5. 伴生对象中apply方法则为创建对象提供方便,相当于工厂方法。
  6. 伴生对象继承了AbstractFunction

从case类的设计目的来看,最重要的是提供构造器模式匹配(且构造时的参数,与解构的结果一致),另外case类可看作是数据对象,不可变的数据对象。

因为case类封装的数据有不变的特点,以及可以进行模式匹配,所以它在actor中经常使用,很适合封装消息在actor之间传递。

上面列出的几点中,对于第6点“伴生对象继承自 Function”可能感到奇怪,Martin在这里回答了为什么case类的伴生对象会继承FunctionN

The reason why case class companion objects implement FunctionN is that before, case classes generated a class and a factory method, not a companion object. When we added extractors to Scala it made more sense to turn the factory method into a full companion object with apply and unapply methods. But then, since the factory method did conform to FunctionN, the companion object needed to conform, too.

另外,当参数大于2个时,FunctionN 都提供了tupled方法生成一个函数,该函数可以接受一个tuple作为参数构造出结果,比如:

scala> case class A(x: Int, y:Int)

scala> A.tupled
res11: ((Int, Int)) => A = <function1>

scala> val t = (100,100)
t: (Int, Int) = (100,100)

scala> A.tupled(t)
res9: A = A(100,100)
文章转自 并发编程网-ifeve.com

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
只会if-else和switch?多层逻辑判断的优雅写法
只会if-else和switch?多层逻辑判断的优雅写法
35 0
Java接口概念和语法例子(功能性方法)
比如有三个类。兔子、狗、青蛙这三个类。要定义一个公共游泳方法出来。但是兔子不会这个游泳,那么就不使用这个接口,另外的狗和青蛙会游泳,就会使用这个游泳接口。简单来说,就是谁需要功能接口谁就使用这个功能接口就好了
19 0
java核心技术卷中的细节(1- 带下划线的数字、带标签的break)
java核心技术卷中的细节(1- 带下划线的数字、带标签的break)
49 0
用kotlin打印出漂亮的android日志(三)——基于责任链模式打印任意对象
用kotlin打印出漂亮的android日志(三)——基于责任链模式打印任意对象
283 0
方法的定义与使用(方法的基本定义)|学习笔记
快速学习 方法的定义与使用(方法的基本定义)
22 0
重构——39以多态取代条件表达式(Replace Conditional with Polymorphism)
以多态取代条件表达式(Replace Conditional with Polymorphism):你手上有个条件表达式,它根据对象类型的不同而选择不同的行为;将这个条件表达式的每个分支放进一个子类内的覆写函数中,然后将原始的函数声明为抽象函数
2106 0
重构——33以字段取代子类(Replace Subclass with Fields)
以字段取代子类(Replace Subclass with Fields):你的各个子类的唯一差别只在“返回常量数据”的函数上:修改这些函数,使他们返回超类的某个新增字段,然后销毁子类
1148 0
+关注
boxti
12535
文章
问答
文章排行榜
最热
最新
相关电子书
更多
继承与功能组合
立即下载
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载