继续学习,这一篇主要是通过scala来吐槽java的,同样是jvm上的语言,差距咋就这么大呢?
作为一个有.NET开发经验的程序员,当初刚接触java时,相信很多人对java语言有以下不爽(只列了极小一部分):
1. 一堆的setter/getter方法,没有c#中的property属性概念
2. 方法的参数值,不能设置缺省值
3. 不定个数参数的写法太单一
...
然后java的拥护者讲出一堆大道理,说这样设计是如何如何有道理,各种洗脑,时间长了,也就被迫习惯了。要不是遇到scala,我还真就信了,你看看人家scala同学,2003/2004发布的,早就把这些全实现了,而java同学作为jvm上的元老,这些年一直顽固不化,不思进取,已经被jvm上的其它同学远远甩在后面了,java你可长点心吧!进入正题,直接上码:
一、参数缺省值
/**
* 参数缺省值
* @param person
* @param msg
*/
def saySomething(person: String = "somebody", msg: String = "Hello") = {
println(person + " say : " + msg);
}
调用示例:
saySomething()
saySomething("jimmy")
saySomething("jimmy", "hi")
那么,最终编译出来的class,到底是如何实现的呢?可以借助一些反编译工具,比如JD-GUI还原成java一看究竟:
public void saySomething(String person, String msg) {
Predef..MODULE$.println(new StringBuilder().append(person).append(" say : ").append(msg).toString());
}
public String saySomething$default$1() {
return "somebody";
}
public String saySomething$default$2() {
return "Hello";
}
也就是说,scala中的def saySomething(person: String = "somebody", msg: String = "Hello") 如果用java实现的话,可以用3个方法来变相实现,每个缺省参数,相当于一个独立的版本,换言之,在编译器层面,其实java的编译器如果想做,是完全可以做到的,为什么不做?懒!顽!
二、class的property
/**
* 定义一个带参主构造器的类
* @param pReadOnly
*/
class Sample(pReadOnly: String) {
/**
* 可读写的属性
*/
var myProperty: String = _;
private val _readOnly: String = pReadOnly;
/**
* 只读属性
*/
val readOnly: String = _readOnly;
}
调用示例:
val sample = new Sample("test")
println(sample.readOnly)
sample.myProperty = "a new value"
println(sample.myProperty)
没了setter/getter看起来倍儿清爽!还是反编译class看看:
1 public class Sample { 2 private String myProperty; 3 private final String _readOnly; 4 private final String readOnly; 5 6 public String myProperty() { 7 return this.myProperty; 8 } 9 10 public void myProperty_$eq(String x$1) { 11 this.myProperty = x$1; 12 } 13 14 private String _readOnly() { 15 return this._readOnly; 16 } 17 18 public String readOnly() { 19 return this.readOnly; 20 } 21 22 public Sample(String pReadOnly) { 23 this._readOnly = pReadOnly; 24 25 this.readOnly = _readOnly(); 26 } 27 }
可以看到,myProperty自动生成了setter/gettter,仍然是在编译器层面,就可以顺手做掉的事情,java编译器依然不肯做。
三、不定个数参数值
这个问题,java中虽然可以xxx(String[] args)用数组传递达到类似的效果,但是就算传一个空数组,也至少也得写一个xxx(null)吧,既然此时参数都为空了,为啥不直接xxx()更直接,看看scala:
/**
* 不固定个数的参数
* @param x
* @return
*/
def add(x: Int*) = {
var i = 0
for (j <- x) i += j
i
}
调用:
println(add())
println(add(1, 2, 3, 4, 5))
明显的更高端大气上档次,继续反编译,这个要略复杂点:
先是生成了这么一个类:
public final class DefHello$$anonfun$add$1 extends AbstractFunction1.mcVI.sp
implements Serializable
{
public static final long serialVersionUID = 0L;
private final IntRef i$1;
public final void apply(int j)
{
apply$mcVI$sp(j); }
public void apply$mcVI$sp(int j) { this.i$1.elem += j; }
public DefHello$$anonfun$add$1(IntRef i$1)
{
}
}
然后是:
public void main(String[] args)
{
Predef..MODULE$.println(BoxesRunTime.boxToInteger(add(Nil..MODULE$)));
Predef..MODULE$.println(BoxesRunTime.boxToInteger(add(Predef..MODULE$.wrapIntArray(new int[] { 1, 2, 3, 4, 5 }))));
...
}
public int add(Seq<Object> x)
{
IntRef i = IntRef.create(0);
x.foreach(new AbstractFunction1.mcVI.sp() { public static final long serialVersionUID = 0L;
public final void apply(int j) { apply$mcVI$sp(j); }
public void apply$mcVI$sp(int j) { DefHello..this.elem += j; }
});
return i.elem;
}
最终调用时,add()这里虽然scala没有传任何参数,但从反编译结果上看,最终还是变成了add(Nil..MODULE$)),编译器自动加了一个参数,以满足java的规范。
scala 学习笔记(03) 参数缺省值、不定个数参数、类的属性(Property)
原文:http://www.cnblogs.com/yjmyzz/p/4714558.html