scala中val与def定义的区别

scala中val与def定义的区别

变量

val定义一个不可改变的变量, def则是一个方法:

//scala中定义:
def main(args: Array[String]): Unit = {
  def a = "hello"
  val b = "hello"
  println(a)
  println(b)
}

//编译之后的class文件
private final String a$1()
{
  return "hello";
}

public void main(String[] args)
{
  String b = "hello";

  Predef..MODULE$.println(a$1());
  Predef..MODULE$.println(b);
}

方法

下面我们分别对应这四种定义方式,与反编译后的java比较一下,从而深层次理解def与val在方法中怎么实现的

class Test {
  def even1: (Int => Boolean) = (_ % 2 == 0)
  val even2: (Int => Boolean) = (_ % 2 == 0)
  def even3(x: Int): Boolean = {
    x % 2 == 0
  }
  lazy val even4: Int => Boolean = _ % 2 == 0
}

1. def a = ()

def even1: (Int => Boolean) = (_ % 2 == 0), 通过编译我们可以看到,每次调用even1 都会实例化一个对象,这显然不是我们愿意看到的

  public Function1 even1()
  {
    new AbstractFunction1.mcZI.sp()
    {
      public static final long serialVersionUID = 0L;

      public boolean apply$mcZI$sp(int x$1)
      {
        return x$1 % 2 == 0;
      }

      public final boolean apply(int x$1)
      {
        return apply$mcZI$sp(x$1);
      }
    };
  }

2. val =

val even2: (Int => Boolean) = (_ % 2 == 0),实现了Function1, 并且实例化该对象

public Function1 even2()
{
  return this.even2;
}

private final Function1 even2 = new AbstractFunction1.mcZI.sp()
{
  public static final long serialVersionUID = 0L;

  public boolean apply$mcZI$sp(int x$2)
  {
    return x$2 % 2 == 0;
  }

  public final boolean apply(int x$2)
  {
    return apply$mcZI$sp(x$2);
  }
};

3.def a() = {}

这种方法定义相比java比较常规,容易接受

def even3(x: Int): Boolean = {
 x % 2 == 0
}
编译之后如下:    
public class Test
{
  public boolean even3(int x)
  {
    return x % 2 == 0;
  }
}

4.lazy val

lazy val even4: Int => Boolean = _ % 2 == 0,对比even2, 实现了懒加载

  private Function1 even4;
  private volatile boolean bitmap$0;

  public Function1 even4()
  {
    return this.bitmap$0 ? this.even4 : even4$lzycompute();
  }

  private Function1 even4$lzycompute()
  {
    synchronized (this)
    {
      if (!this.bitmap$0)
      {
        this.even4 = new AbstractFunction1.mcZI.sp()
        {
          public static final long serialVersionUID = 0L;

          public boolean apply$mcZI$sp(int x$1)
          {
            return x$1 % 2 == 0;
          }

          public final boolean apply(int x$1)
          {
            return apply$mcZI$sp(x$1);
          }
        };this.bitmap$0 = true;
      }
      return this.even4;
    }
  }

我们再看一个比较复杂的例子

方法里面定义方法

class Test {
  def fun1(x: Int): Int = {
    def fun1_2() = {
      println("fun1_2=>" + x)
    }

    fun1_2()
    println("fun1")
    2 * x
  }

  val fun2 = (x: Int) => {
    val fun2_2 = () => {
      println("fun2_2=>" + x)
    }
    fun2_2()
    println("fun2")
    2 * x
  }
}

反编译后的java代码如下:

public class Test
{
  private final void fun1_2$1(int x$1)
  {
    Predef..MODULE$.println(new StringBuilder().append("fun1_2=>").append(BoxesRunTime.boxToInteger(x$1)).toString());
  }

  public int fun1(int x)
  {
    fun1_2$1(x);
    Predef..MODULE$.println("fun1");
    return 2 * x;
  }

  public Function1 fun2()
  {
    return this.fun2;
  }

  private final Function1 fun2 = new AbstractFunction1.mcII.sp()
  {
    public static final long serialVersionUID = 0L;

    public final int apply(int x)
    {
      return apply$mcII$sp(x);
    }

    public int apply$mcII$sp(final int x)
    {
      Function0 fun2_2 = new AbstractFunction0.mcV.sp()
      {
        public static final long serialVersionUID = 0L;

        public final void apply()
        {
          apply$mcV$sp();
        }

        public void apply$mcV$sp()
        {
          Predef..MODULE$.println(new StringBuilder().append("fun2_2=>").append(BoxesRunTime.boxToInteger(x)).toString());
        }
      };
      fun2_2.apply$mcV$sp();
      Predef..MODULE$.println("fun2");
      return 2 * x;
    }
  };
}

从例子可以看出来, def方法比较简单唯一的区别是,把方法提出去形成并列的两个方法,把这种闭包形式通过形参的方式传递给下一个方法, 而val方法通过实例化Function1接口来实现,对于fun2_2每次调用都会实例化对象,这个使我们编程中需要注意的

你可能感兴趣的:(scala,val与def,scala,java)