Scala类详解

来源:互联网 发布:雅漾活泉保湿面膜 知乎 编辑:程序博客网 时间:2024/05/17 01:20
一个简单的Scala类:
class Person {    private var name: String = _    private var age = 0    def this(name: String, age: Int) { //实际上this是重载了主构造器,使用new Person()依然可以创建对象        this //默认构造器,即主构造器,class Person实际上省略了(),class Person()是主构造器        this.name = name        this.age = age    }    def getName() = name //或则def getName = name    def setName(name: String) { this.name = name }}object ClassTest {    def main(args: Array[String]): Unit = {        val a = new Person()        println(a.getName())        val b = new Person("zero", 18)        println(b.getName())    }}
运行结果:
nullzero
如注释,this方法是重载了主构造器,使用new Person()依然可以创建对象,在this方法中必须先调用this默认构造器,即主构造器,class Person实际上省略了(),class Person()是主构造器。和Java不一样,这里new Person()依然可以创建对象,如果想禁掉这种创建类的方式可以这样:
class Person private () {    private var name: String = _    private var age = 0    def this(name: String, age: Int) {        this        this.name = name        this.age = age    }    def getName() = this.name    def setName(name: String) { this.name = name }}
需要注意的是,在这种方式下定义类成员时必须要显式的指明初始值

当然还可以更简单的定义这个Person类:
class Person(val name: String, var age: Int, gender: String, number: Int) {    def getNumber() = this.number;}object ClassTest {    def main(args: Array[String]): Unit = {        val b = new Person("zero", 18, "男", 7)        b.age_=(20)        println(b.name)        println(b.age)    }}
使用jd-gui-windows-1.4.0(一下简称jd-gui)反编译Person.class后的结果如下:
public class Person{  private final String name;   public String name(){    return this.name;  }   public int age(){    return this.age;  }   public void age_$eq(int x$1){    this.age = x$1;  }   public int getNumber(){    return this.number;  }   public Person(String name, int age, String gender, int number) {}}
再使用javap –private Person.class反编译结果如下:
public class com.zero.clazz.Person {  private final java.lang.String name;  private int age;  private final int number;  public java.lang.String name();  public int age();  public void age_$eq(int);  public int getNumber();  public com.zero.clazz.Person(java.lang.String, int, java.lang.String, int);}
结合两个工具的反编译结果分析:Scala自动将这个类变成了public,在Scala中任何没有标记为private或则protected的数据都默认为public。Scala将声明为var的age成员用private修饰,并对外提供getter和setter方法用以取值和赋值(在Scala中,getter和setter分别叫做age和age_=,默认的getter和setter是由Scala自动生成),将声明为val的成员用private final修饰,并对外提供getter方法用以取值。对于既不是var也不是val的成员,如果在类中没有被使用,那么就忽略了该字段,如果被使用了(只能够取值不能赋值),那个该字段就晋升为类的成员,被private final修饰。

如果不想由Scala生成getter和setter方法呢?
class Person(val name: String) {    private var age = 0    private[this] var gender: String = "男"}
javap反编译结果:
public class com.zero.clazz.Person {  private final java.lang.String name;  private int age;  private java.lang.String gender;  public java.lang.String name();  private int age();  private void age_$eq(int);  public com.zero.clazz.Person(java.lang.String);}
可以发现,private [this] var gender类似于定义对象的私有字段,其他同一个类的对象也无法访问到,Scala不会生成getter或setter方法。

关于构造函数
class Person(val name: String, var age: Int, gender: String) {    private var firstName: String = _    def this(name: String, age: Int, gender: String, firstName: String) {        this(name, age, gender)        this.firstName = firstName        println("construct_02")    }    println("construct_01")    override def toString(): String = {        age + " zero " + firstName    }}object ClassTest {    def main(args: Array[String]): Unit = {        val a = new Person("zero", 18, "男")        println(a)        val b = new Person("zero", 18, "男", "007")        println(b)    }}
运行结果:
construct_0118 zero nullconstruct_01construct_0218 zero 007
jd-gui反编译后的Person:
public class Person{  private final String name;  private String firstName;   public String name(){    return this.name;  }   public int age(){    return this.age;  }   public void age_$eq(int x$1){    this.age = x$1;  }   private String firstName(){    return this.firstName;  }   private void firstName_$eq(String x$1){    this.firstName = x$1;  }   public Person(String name, int age, String gender, String firstName){    this(name, age, gender);    firstName_$eq(firstName);    Predef..MODULE$.println("construct_02");  }   public Person(String name, int age, String gender){    Predef..MODULE$.println("construct_01");  }   public String toString(){    return new StringBuilder().append(age()).append(" zero ").append(firstName()).toString();  }}
javap反编译后的结果:
public class com.zero.clazz.Person {  private final java.lang.String name;  private int age;  private java.lang.String firstName;  public java.lang.String name();  public int age();  public void age_$eq(int);  private java.lang.String firstName();  private void firstName_$eq(java.lang.String);  public java.lang.String toString();  public com.zero.clazz.Person(java.lang.String, int, java.lang.String);  public com.zero.clazz.Person(java.lang.String, int, java.lang.String, java.lang.String);}
发现实际上scala生成了两个构造函数,主构造函数Person(String name, int age, String gender),辅助构造器也调用了主构造函数,主构造函数会将类{}里面的语句纳入到其方法类。

如果喜欢传统的JavaBean风格的getter与setter,可以这样:
class Person(@BeanProperty val name: String,        @BeanProperty var age: Int,        @BeanProperty gender: String) {}
javap反编译结果:
public class com.zero.clazz.Person {  private final java.lang.String name;  private int age;  public java.lang.String name();  public int age();  public void age_$eq(int);  public void setAge(int);  public java.lang.String getName();  public int getAge();  public com.zero.clazz.Person(java.lang.String, int, java.lang.String);}
可以发现将会生成四个方法,除了Scala默认的setter和getter方法,还有JavaBean风格的getter与setter方法。



0 0
原创粉丝点击