开始接触学习Scala,边学边记。
作为参考和对比,首先从Java的POJO开始;
定义一个Person类(为防止和Scala的Person类重名冲突,将该类放在gao.java目录下),如下:
package gao.java; public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
我们可以使用javap查看一下Person类编译后的Person.class文件:
$ javap -p target/scala-2.11/classes/gao/java/Person.class Compiled from "Person.java" public class gao.java.Person { private java.lang.String name; private int age; public gao.java.Person(java.lang.String, int); // 构造方法 public java.lang.String getName(); // getter方法 public void setName(java.lang.String); // setter方法 public int getAge(); // getter方法 public void setAge(int); // setter方法 }
再来看看Scala如何定义Person类(在gao目录下):
package gao class Person(var name:String, var age:Int)
哇塞!这就完了?相信大多数人第一次见到都会和我一样好奇。非常的简单!
我们也使用javap查看一下该Scala类编译后的Person.class文件:
$ javap -p target/scala-2.11/classes/gao/Person.class Compiled from "Person.scala" public class gao.Person { private java.lang.String name; private int age; public java.lang.String name(); // getter方法 public void name_$eq(java.lang.String); // setter方法 public int age(); // getter方法 public void age_$eq(int); // setter方法 public gao.Person(java.lang.String, int); // 构造方法 }
(1)在.class文件中,除了getter/setter方法的方法名看起来比较别扭之外,其他没有什么不同;
(2)不过.class文件是给JVM看的,而对JVM来说,只要是有效的方法名,又有什么区别呢。
(3)对于程序员来说,编码效率相对提高了很多(27行=>2行)。
(4)属性的访问修饰符自动编译为private。
(5)getter/setter方法自动编译为public。
Scala的方法调用也非常简单,为了简便,演示如下:
package gao object Main { def main(args: Array[String]) { val person = new Person("Jack", 28) println(person.name) // 调用getter方法,然后打印到标准输出 println(person.age) // 调用getter方法,然后打印到标准输出 person.name = "Rose" // 调用setter方法赋值 person.age = 27 // 调用setter方法赋值 println(person.name) // 再调用getter方法,然后打印到标准输出 println(person.age) // 再调用getter方法,然后打印到标准输出 } }
输出如下:
Jack 28 Rose 27
再使用javap查看一下这个Main.class文件,发现它只有一个Java的main方法:
$ javap -p target/scala-2.11/classes/gao/Main.class Compiled from "Main.scala" public final class gao.Main { public static void main(java.lang.String[]); }
在Scala中,分别使用val和var来声明值和变量。
所谓值就是常量,不可变量。还是使用代码来演示比较清晰,修改Scala的Person类如下:
package gao class Person(val name:String, var age:Int)
其实这还看不出什么差别,不过通过方法调用就很容易看出不同,如图所示,不能给val修饰的属性赋值;
为什么呢?
这还是要使用javap来的比较清楚:
$ javap -p target/scala-2.11/classes/gao/Person.class Compiled from "Person.scala" public class gao.Person { private final java.lang.String name; private int age; public java.lang.String name(); public int age(); public void age_$eq(int); public gao.Person(java.lang.String, int); }
原来val修饰的字段被编译成final的,而且不会有setter方法,所以不能赋值。
Scala建议在赋值时,优先选择使用val,在必须使用var的情况下再使用var。
从上边示例看出,Scala编译器自动将类字段的访问修饰符编译为private。
那如果我们在代码中,显式的类字段标识为private会怎样呢?
package gao class Person(val name:String, var age:Int) { private val legs = 4 var brother = 2 }
使用javap查看编译后的.class文件内容:
$ javap -p target/scala-2.11/classes/gao/Person.class Compiled from "Person.scala" public class gao.Person { private final java.lang.String name; private int age; private final int legs; private int brother; public java.lang.String name(); public int age(); public void age_$eq(int); private int legs(); // getter方法私有,外部不能访问,只能在内部使用,还弄个getter方法干什么用? public int brother(); // getter方法 public void brother_$eq(int); // setter方法 public gao.Person(java.lang.String, int); }