scala基础4 —— 类

来源:互联网 发布:linux 时间格式转换 编辑:程序博客网 时间:2024/05/11 17:53

scala的类定义和java差不多,只是要更为灵活一些。
在scala中,类的声明不需要public关键字,一个文件中可以声明多个类,而这些类都是公共可见的。
比如,构造一个账户类,里面有值保存余额:

class Account {  private var value = 0 // 成员必须初始化  def add(x : Int) { value += x} // 方法默认是public的  def current() = value}// 对类的使用Account myAccount = new Account() // 或者new AccountmyAccount.add(50)myAccount.current // 调用无参方法可以不需要括号

关于类方法的调用

scala对象调用方法时,对于无参方法,可以选择要不要加括号,一般的习惯是要修改(set)成员变量,则加括号;要仅仅获取(get)成员值,则习惯不加括号。
另,如果类方法在声明的时候就没有括号(这在scala中也是可以的),那么调用时候也不能加括号。

getter和setter

对于java程序,我们一般习惯将成员变量设置为private的,并且提供getter和setter方法来对成员变量进行操作。
而在scala中,getter和setter方法时编译自动完成的,其中访问控制(public,private)和变量的访问控制相同,当然,也可以自己重新定义getter和setter方法,不过名字不是getXXX和setXXX,而是xxx和xxx_=。比如:

class Person {  var age : Int = 0}object Main {  def main(args: Array[String]): Unit = {    var p = new Person    println(p.age)  // 调用p.age()    p.age = 10 // 调用p.age_=(10)  }}

scala的这种设计符合统一访问原则(某个模块提供的所有服务都应该能通过统一的表示法访问到,通过什么方式实现,应该让使用者无感知),在上述例子中,p.age不知道是通过字段还是方法访问到的。

字段访问控制

  1. 类某个字段是私有的,则getter和setter也是私有的;
  2. 如果字段是val的,则只有getter方法生成;
  3. 如果不需要任何getter和setter,可以将字段声明为private[this]
  4. scala的类方法可以访问该类所有其他对象的私有字段,如果字段声明为private[this],则只有当前对象能访问,比如:
class Person {  private var age : Int = 0  private[this] var name : String = ""  def changeAge(p : Person): Unit = {    this.age = p.age    // OK  }  def changeName(p : Person): Unit = {    this.name = p.name  // ERROR  }}

构造函数

scala和java一样可以有多个构造函数,但是不一样的地方是,scala有一个特别的构造函数,就是primary constructor(主构造器)。
每个类都有主构造器,并且,主构造器不是this方法定义,而是和类的定义交织在一起,其参数直接放在类名之后,比如:

class Person (var age : Int, val name : String) {  println("this is in primary constructor!") // 类中定义的所有语句都会在主构造器中调用}object Main {  def main(args: Array[String]): Unit = {    val p = new Person(10, "Jack") // 必须传入参数构造    println(p.age)  }}

当然,如果类名后无参数,生成的就是一个默认的无参主构造器,scala类主构造器的声明和类普通成员变量声明形式一样,主要与以下几种:

声明方式 对应生成的字段和方法 name : String 对象私有字段,如果该字段没有被使用,则不会有该字段 val/var name : String 私有字段,公有的getter/setter方法 private val/var name : String 私有字段,私有的getter/setter方法 @BeanPropertiy val/var name : String 私有字段,公有的java版和scala版getter/setter方法

如果主构造器成员变量声明让你不容易接受,你可以使用普通方式,即辅助构造器this()来声明一个或者多个构造函数,但是我们应该学会习惯并使用主构造器,因为,scala追求的简洁我们应该要学会利用。
另,如果要让主构造器为私有的,可以如下定义:

class Person private(var age : Int, val name : String) { // 注意private关键字  println("this is in primary constructor!") }

嵌套类

scala中可以在类中定义嵌套类,但是和java的嵌套类有一些不同,scala中的内部类属于外部类的实例,即不同实例的内部类类型时不一样的;而java中内部类从属于外部类,下面从我们从一个家庭类Family和成员类Member来看看java和scala的不同:
java内部类:

public class Family {    private String familyName;    private List<Member> memberList = new ArrayList<>();    public Family(String familyName) {        this.familyName = familyName;    }    public void jionMember(Member member) {        memberList.add(member);    }    public class Member {        private String name;        public Member(String name) {            this.name = name;            System.out.println(familyName + " new member:" + this.name);        }    }    public static void main(String[] args) {        Family family = new Family("Jack's family");        Family family1 = new Family("Mark's family");        Member member = family.new Member("jackson"); // 注意声明语法        Member member1 = family1.new Member("mark");  // 注意声明语法        family.jionMember(member);  // OK        family.jionMember(member1); // OK    }}

scala内部类

class Family (var familyName : String) {  private var memberList : mutable.MutableList[Member] = mutable.MutableList()  def jionMember(member: Member): Unit = {    memberList += member  }  class Member (var name : String) {    println(familyName + " new family member:" + name)  }}object Family {  def main(args: Array[String]) {    var family = new Family("Jack's family")    var family1 = new Family("Mark's family")    val member : family.Member = new family.Member("jack") // 注意声明语法    val member1 : family1.Member = new family1.Member("Mark")    family.jionMember(member)    family.jionMember(member1) // 不可以  }}

从上面可以看出,scala中不允许不同外部类的实例声明的内部类混合使用。
如果想打破这种限制,可以将内部类放在别处,比如Family类的伴生对象中,或者使用类型投影方式(暂不介绍)。

0 0
原创粉丝点击