购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.5 类和对象

1.5.1 类的定义

我们已经知道,对象是类的具体实例,类是抽象的,不占用内存;而对象是具体的,占用存储空间。

Scala中一个简单的类定义是使用关键字class,类名必须大写。类中的方法用关键字def定义,例如以下代码:

    class User{
       private var age=20
       def count(){
         age+=1
       }
    }

如果一个类不写访问修饰符,那么默认访问级别为Public,这与Java是不同的。

关键字new用于创建类的实例。例如,调用上述代码中的count()方法,可以使用以下代码:

    new User().count()

1.5.2 单例对象

Scala中没有静态方法或静态字段,但是可以使用关键字object定义一个单例对象。单例对象中的方法相当于Java中的静态方法,可以直接使用“单例对象名.方法名”的方式进行调用。单例对象除了没有构造器参数外,可以拥有类的所有特性。

例如以下代码定义了一个单例对象Person,该对象中定义了一个方法showInfo():

    object Person{
      private var name="zhangsan"
      private var age=20
      def showInfo():Unit={
       println("姓名:"+name+",年龄:"+age)
      }
    }

可以在任何类或对象中使用代码Person.showInfo()对方法showInfo()进行调用。

1.5.3 伴生对象

当单例对象的名称与某个类的名称一样时,该对象被称为这个类的伴生对象。类被称为该对象的伴生类。

类和它的伴生对象必须定义在同一个文件中,且两者可以互相访问其私有成员。例如以下代码:

    class Person() {
      private var name="zhangsan"
      def showInfo(){
        //访问伴生对象的私有成员
        println("年龄:"+Person.age)
      }
    }
    object Person{
      private var age=20
      def main(args: Array[String]): Unit = {
        var per=new Person()
        //访问伴生类的私有成员
        println("姓名:"+per.name)
        per.showInfo()
      }
    }

运行上述伴生对象Person的main方法,输出结果如下:

    姓名:zhangsan
    年龄:20

1.5.4 get和set方法

Scala默认会根据类的属性的修饰符生成不同的get和set方法,生成原则如下:

· val修饰的属性,系统会自动生成一个私有常量属性和一个公有get方法。

· var修饰的属性,系统会自动生成一个私有变量和一对公有get/set方法。

· private var修饰的属性,系统会自动生成一对私有get/set方法,相当于类的私有属性,只能在类的内部和伴生对象中使用。

· private[this]修饰的属性,系统不会生成get/set方法,即只能在类的内部使用该属性。

例如有一个Person类,代码如下:

    class Person {
      val id:Int=10
      var name="zhangsan"
      private var gender:Int=0
      private[this] var age:Int=20
    }

将该类编译为class文件后,再使用Java反编译工具将其反编译为Java代码,代码如下:

    public class Person{
      private final int id = 10;
      public int id()
      {
       return this.id;
      }
       
      private String name = "zhangsan";
      public String name()
      {
       return this.name;
      }
      public void name_$eq(String x$1)
      {
       this.name = x$1;
      }
       
      private int gender = 0;
      private int gender()
      {
       return this.gender;
      }
      private void gender_$eq(int x$1)
      {
       this.gender = x$1;
      }
       
      private int age = 20;
    }

使用name属性举例,在Scala中,get和set方法并非被命名为getName和setName,而是被命名为name和name_=,由于JVM不允许在方法名中出现=,因此=被翻译成$eq。

从上述代码可以看出,由于属性id使用val修饰,因此不可修改,只生成了与get方法对应的id();属性name使用var修饰,因此生成了与get和set方法对应的name()和name_$eq()方法,且都为public;属性gender由于使用private var修饰,因此生成了private修饰的get和set方法;属性age由于使用private[this]修饰,因此没有生成get和set方法,只能在类的内部使用。

此时可以使用如下代码对Person类中的属性进行访问:

    object test{
      def main(args: Array[String]): Unit = {
       var per:Person=new Person()
       
       per.name="lisi"
       println(per.id)
       println(per.name)              //将调用方法per.name()
       
       per.id=20                      //错误,不允许修改
      }
    }

除了系统自动生成get和set方法外,也可以手动进行编写,例如以下代码:

    class Person {
      //声明私有变量
      private var privateName="zhangsan"
      //定义get方法
      def name=privateName
      //定义set方法
      def name_=(name:String): Unit ={
       this.privateName=name
      }
       
    }
    object test{
      def main(args: Array[String]): Unit = {
       var per:Person=new Person()
       //访问变量
       per.name="lisi"                //修改
       println(per.name)              //读取
      }
    }

当然也可以使用如下Java风格定义get和set方法:

    class Person {
      //声明私有变量
      private var name="zhangsan"
      //定义get方法
      def getName(): String ={
       this.name
      }
      //定义set方法
      def setName(name:String): Unit ={
       this.name=name
      }
       
    }
    object test{
      def main(args: Array[String]): Unit = {
       var per:Person=new Person()
       //访问属性
       per.setName("wangwu")
       println(per.getName())
      }
    }

1.5.5 构造器

Scala中的构造器分为两种:主构造器和辅助构造器。

1.主构造器

主构造器的参数直接放在类名之后,且将被编译为类的成员变量,其值在初始化类时传入。例如以下代码:

    //定义主构造器,age默认为18
    class Person(val name:String,var age:Int=18) {
       
    }
    object Person{
      def main(args: Array[String]): Unit = {
       //调用构造器并设置name和age字段
       var per=new Person("zhangsan",20)
       println(per.age)
       println(per.name)
       per.name="lisi"//错误,val修饰的变量不可修改
      }
    }

可以通过对主构造器的参数添加访问修饰符来控制参数的访问权限。例如以下代码,将参数age设置为私有的,参数name设置为不可修改的(val):

    class Person(val name:String, private var age:Int) {
    }

构造参数也可以不带val或var,此时默认为private[this] val,代码如下:

    class Person(name:String,age:Int) {
    }

在主构造器被执行时,类定义中的所有语句同样会被执行。例如以下代码中的println语句是主构造器的一部分,每当主构造器被执行时,该部分代码同样会被执行,可以在这里做一些类的初始化工作:

    class Person(var name:String,var age:Int) {
      println(name)
      println(age)
      //初始化语句
    }

如果需要将整个主构造器设置为私有的,那么只需要添加private关键字即可,例如以下代码:

    class Person private(var name:String,var age:Int) {
    }
注意

主构造器也可以没有参数,一个类中如果没有显式地定义主构造器,就默认有一个无参构造器。

2.辅助构造器

Scala类除了可以有主构造器外,还可以有任意多个辅助构造器。辅助构造器的定义需要注意以下几点:

· 辅助构造器的方法名称为this。

· 每一个辅助构造器的方法体中必须首先调用其他已定义的构造器。

· 辅助构造器的参数不能使用var或val进行修饰。

例如以下代码定义了两个辅助构造器:

    class Person {
      private var name="zhangsan"
      private var age=20
      //定义辅助构造器一
      def this(name:String){
       this()               //调用主构造器
       this.name=name
      }
      //定义辅助构造器二
      def this(name:String,age:Int){
       this(name)           //调用辅助构造器一
       this.age=age
      }
    }

上述构造器可以使用如下三种方式进行调用:

    var per1=new Person             //调用无参主构造器
    var per2=new Person("lisi")     //调用辅助构造器一
    var per3=new Person("lisi",28)  //调用辅助构造器二

除此之外,主构造器还可以与辅助构造器同时使用,在这种情况下,一般辅助构造器的参数要多于主构造器,代码如下:

    //定义主构造器
    class Person(var name:String,var age:Int) {
      private var gender=""
      //定义辅助构造器
      def this(name:String,age:Int,gender:String){
       this(name,age)            //调用主构造器
       this.gender=gender
      }
    }
    object Person{
      def main(args: Array[String]): Unit = {
       //调用辅助构造器
       var per=new Person("zhangsan",20,"male")
       println(per.name)
       println(per.age)
       println(per.gender)
      }
    }

上述代码运行的输出结果为: XNA0s/9tzkKyFj20qk4Vd7zdUo6Nut4FiV+pOhPYTpJ/DMyEC2T2dOrEDQe8O00a

    zhangsan
    20
    male
点击中间区域
呼出菜单
上一章
目录
下一章
×