字节Scala面试题(2) --- 伴生对象

今天继续之前字节面试的另外一个问题 --- 伴生对象。

 

----------分界线:面试问题----------

 

请描述一下,Scala中伴生对象编译成.class文件后与伴生类的关系。

 


 

----------分界线:背景知识----------

 

在开始面试问题的详解前,我们需要先了解以下的背景知识:

  1. Scala的编译过程大致分为几步?

  2. 什么是伴生对象及伴生类?

  3. 什么时候存在伴生对象?

 

1. Scala的编译过程大致分为几步?

Scala是Java包装的一种语言;相对Java来说写法要简化很多。Scala的编译也是基于JVM的。下图[Ref -1]是Scala与Java编译过程的一个简易比较。后面会专门找一期写Scala的编译过程;当前仅需要知道一点: .scala文件跟.java的编译过程相似,通过各自的编译器都会被编译成.class文件。伴生类A会被编译成A.class,其伴生对象会被编译成A$.class。

 

2. 什么是伴生对象以及伴生类?

简要来说,在同一个.scala文件中,如果一个class类与一个object单例类完全同名,那么这个object就是这个class的伴生对象,而这个class就是这个object的伴生类。反之,若一个object没有伴生类(与它同名的class),则这个object被称为孤立对象

那么伴生对象有什么用?它又有什么特点呢?

熟悉Scala语法的小伙伴可能注意到了。与Java不同,Scala中没有static关键字,而为了达到与static一样的效果,Scala向我们展示了一种新的方法,就是object,object里面的属性跟方法可以理解为就是static的。

1. 从语法角度来讲,所谓的伴生对象其实就是类的静态方法和成员的集合

2. 从技术角度来讲,scala 还是没有生成静态的内容,只不过是将伴生对象生成了一个新的类,实现属性和方法的调用。

3. 从底层原理看,伴生对象实现静态特性是依赖于 public static final MODULE$ 实现的。

 

伴生类跟伴生对象的一个特点是它们之间的私有成员(除了被用private[this]修饰的外)是可以相互访问的。

 

3. 什么时候存在伴生对象?

这个问题,不多解释直接测试给结论。

Scala中存在的几种类型,class/object/case class。这三种类型中,哪些默认存在伴生对象/伴生类呢?

 

我们首先先依次定义以下三个类型然后在sbt中编译

object CompanionTestObject {
  var objectVal: Int = 1
  val objectVar: Int = 2
  def objectFunc: Int = objectVar + objectVal
}
class CompanionTestClass {
  var classVal: Int = 1
  val classVar: Int = 2
  def classFunc: Int = classVar + classVal
}
case class CompanionTestCaseClass(var caseVar: Int = 1, caseVal: Int = 2) {
  def caseFunc: Int = caseVar + caseVal
}

 

 

编译后(Intellij一般默认将.class文件输出到target\scala-2.13\classes\),我们可以看到有以下.class文件

文章之前提到过,伴生对象的.class会有$的尾缀。所以可以得出结论:

object跟case class在编译后会同时生成伴生类跟伴生对象,一般的class则不会默认生成伴生对象。


 


----------分界线:以下是实际面试问题解析----------

 

请描述一下,Scala中伴生对象编译成.class文件后与伴生类的关系。

 

先给结论:

Scala 的伴生对象和伴生类,从编译的角度看是独立的 。只是它们用了共同的名字。两者实际上只是共享了一个类名,而伴生对象替伴生类保存着一些 “静态”变量和方法,充当着仓库的作用 。

 

为了理解上述结论,再来做一个实验。我们对背景问题3的代码稍作修改,给CompanionTestClass 加一个伴生对象,然后查看反编译的结果。

class CompanionTestClass {
  var classVal: Int = 1
  val classVar: Int = 2
  def classFunc: Int = classVar + classVal
}
object CompanionTestClass { // 新增CompanionTestClass的伴生对象
  def classCompanionDef(): Unit = println("this is a companion for a class")
}

 

反编译.class的结果如下:

 

伴生类CompanionTestClass.class

package test;
​
import scala.reflect.*;
​
@ScalaSignature(bytes = "\u0006\u0005E2A\u0001D\u0007\u0001!!)q\u0003\u0001C\u00011!91\u0004\u0001a\u0001\n\u0003a\u0002b\u0002\u0011\u0001\u000
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值