您的位置:首页 > 其它

scala中val与def定义的区别

2018-02-06 12:06 204 查看

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<Object, Object> 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<Object, Object> even2()
{
return this.even2;
}

private final Function1<Object, Object> 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<Object, Object> even4;
private volatile boolean bitmap$0;

public Function1<Object, Object> 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<Object, Object> fun2()
{
return this.fun2;
}

private final Function1<Object, Object> 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每次调用都会实例化对象,这个使我们编程中需要注意的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: