方法与字段有什么区别?

时间:2016-09-11 11:40:22

标签: scala

在Java中,它们之间的区别很明显。但是在Scala中,可以声明和使用方法而不用括号。我也知道统一访问原则是Scala的理念。这些都使得场和方法之间的界限模糊到一个新的学习者。

一开始,我认为defval是方法和字段之间的边界。但事实证明,在Scala中,使用val在子类中定义的“field”可以覆盖使用def在基类中定义的“方法”,这在我知道区分字段概念的任何语言中都是不可能的和方法。

因此我想知道:

  1. Scala中“字段”的概念是否不存在(或完全与无参数方法相同)?

  2. 如果没有,他们之间的界限是什么?

3 个答案:

答案 0 :(得分:4)

这很简单。例如,对于公共val scalac生成私有字段来保存值,以及getter。

class A {
  val x = 4
}

在javap中你可以看到

public class A {
  private final int x;
  public int x();
  public A();
}

所以,如果你有

trait T { def x = 1 }

class A extends T { val x = 4 }

您正在将特征x中的方法T覆盖为getter x到私有字段x

答案 1 :(得分:2)

主要差异

def f: Int = something

val v = 1

f是一种不立即评估的方法。每次显式调用或调用f时都会评估f,其中v会立即进行评估。

通知f在声明时不会被评估,但在声明时会立即评估x。在显式调用时会对f进行评估。

scala> val x = { println("evaluated"); 1}
evaluated
x: Int = 1

scala> def f = { println("evaluated"); 1}
f: Int

scala> f
evaluated
res0: Int = 1

scala> f
evaluated
res1: Int = 1

继承

trait A {
  def m: Unit
}

class B extends A {
 override val m: Unit = something
}

def可以覆盖为val,但反之亦然。我们能够这样做,因为声明val m会生成一个名为m的方法。所以它就像在子类型中声明m来覆盖超类型中的什么。

答案 2 :(得分:2)

在编译器中打开-print选项时会很清楚:

def m = List(1,2,3)

=> 

object iw extends Object {
  def m(): List = 
    scala.collection.immutable.List.apply(
      scala.Predef.wrapIntArray(Array[Int]{1, 2, 3})
    );
  def <init>(): type = {
    iw.super.<init>();
    ()
  }
}

VS

val v = List(1,2,3)

=>

object iw extends Object {
  private[this] val v: List = _;
  <stable> <accessor> def v(): List = iw.this.v;
  def <init>(): type = {
    iw.super.<init>();
    iw.this.v =
      scala.collection.immutable.List.apply(
        scala.Predef.wrapIntArray(Array[Int]{1, 2, 3})
      );
  ()
}

}

两者都有效地定义了一个方法,但在后一种情况下,私有变量的初始化立即发生,你只需得到它的值,而在每次调用它时都是前者。