鲁春利的工作笔记,好记性不如烂笔头



类:

    类是对象的模板,通过构造类,能够使用new关键字声明一系列同结构的对象。

对象:

    除了使用类构造对象模板,还可以使用object构造单例对象。

继承:

    继承是类的拓展。

特质:

    类似于java中的接口,但是可以包含实现方法。一个类只能集成自一个父类,但可以拓展自多个特质。


1、类定义

class HelloWorld {
    private val value1 = "hello";    // 属性声明
    var value2 = "world";            // 属性声明
    // 函数定义
    def add () {
        println(value1 + value2);
    }
    def plus (m : Char) = value2 + m;
}

    类成员主要包括字段(val和var)、方法/函数(def);

    类成员可见性有两种,private和public(默认),private需要声明;

    类声明后通过new声明对象:val one = new HelloWorld;

    对象的操作:

scala> val a = one.value1;
<console>:10: error: value value1 in class HelloWorld cannot be accessed in HelloWorld
       val a = one.value1;
                   ^
scala> val b = one.value2;
b: String = world

scala> one.value2 = one.plus('H');
one.value2: String = worldH

scala> one.add();
helloworldH

// 调用无参方法时可以不带()
scala> one.add;
helloworldH

// 若类中声明无参方法时不带(),实际调用时也不可带
... def add {println(value1 + value2);}
one.add;

    Scala中class的缺省修饰符为public(public,protected,private),类的方法以def定义开始,要注意的是Scala方法的参数都是val类型,而不是var类型,因此在函数体内不可以修改参数的值。

    类的方法分两种,一种是有返回值的,一种是不含返回值的。不需要返回值的方法,Scala内部其实将这种函数的返回值定为Unit(类同Java的void类型),但可以省略掉“=”号。

    Scala代码无需使用“;”结尾,也不需要使用return来返回值,函数最后一行的值就作为函数的返回值。


2、getter和setter方法

    Scala对每个类中的字段都提供getter和setter方法,getter方法和setter方法便于控制类中私有对象的数据,通过getter和setter方法可以获取、有限制的修改私有字段。

    对于公有字段来说,其getter和setter方法是公有的,对于私有字段来说,则是私有的;

    var声明的字段带有getter和setter方法(读写);

    val声明的字段只带有getter方法(只读);

private val value1 = "hello";    // 属性声明
var value2 = "world";            // 属性声明

    对于字段value1,其getter形式为value1,无setter方法;

    对于字段value2,其getter和setter方法形式为value2和value2_=;

    实际使用中,var变量的getter和setter方法是一致的,形如value2=xxx。

scala> class HelloWorld {
     |     private var privatevalue1 = "hello";
     |     var value2 = "world";
     |     def add() {
     |         println(value1 + "\t" + value2);
     |     }
     |     def plus (m : Char) = value2 + m;
     |     def value1 = privatevalue1;        // 修改private属性的值
     |     def value1_ (newvalue : String) = {
     |         privatevalue1 = newvalue;
     |     }
     | }
defined class HelloWorld

scala> val one = new HelloWorld;
one: HelloWorld = HelloWorld@319edff2

scala> one.add;
hello   world

scala> one.plus('!');
res45: String = world!

scala> one.value1_("new");

scala> one.add;
new     world


3、查看Scala生成的字节码

    创建Person类保存到Person.scala文件中,内容如下: 

import scala.reflect.BeanProperty;
class Person {
        private val age : Int = 0;
	var name : String = "";
	@BeanProperty var address : String = "";
}

    通过scalac编译成class文件

G:\Hadoop\scala-SDK\source>scalac Person.scala

    编译后使用javap查看生成的字节码,可以验证Scala生成的getter和setter方法:

G:\Hadoop\scala-SDK\source>E:\OW\jdk1.7\bin\javap -private Person.class
Compiled from "Person.scala"
public class Person {
  // val对应java的final
  private final int age;
  // var为普通的属性
  private java.lang.String name;
  private java.lang.String address;
  
  // val类型的age变量只有getter方法
  private int age();
  
  // var类型的name变量具有getter和setter方法,=号被表示为$eq
  public java.lang.String name();
  public void name_$eq(java.lang.String);
  
  // var类型的address同时生成scala和java的getter和setter方法
  public java.lang.String address();
  public void address_$eq(java.lang.String);
  // 以及Java格式的getter和setter方法
  public void setAddress(java.lang.String);
  public java.lang.String getAddress();
  
  // 生成默认的构造方法
  public Person();
}

       

4、构造器

    每个类都有主构造器,且与类定义交织在一起;

    主构造器的参数直接放置在类名之后;

class HelloWorld (val value1 : String, val value2 : String) {......}

    主构造器的参数被编译成字段,并在构造对象时初始化传入;

    一个类若没有显式定义构造器则自动拥有一个无参构造器;

    若类中有直接执行的语句(非定义的方法、函数),每次构造对象时执行一次。

scala> class HelloWorld (val value1 : String, val value2 : String) {
     |     println("receive params : " + value1 + ", " + value2);
     |     val value3 = value1 + value2;
     | }
defined class HelloWorld

scala> val one = new HelloWorld("Hello", "World");
receive params : Hello, World
one: HelloWorld = HelloWorld@d103dac

scala> one.value3;
res48: String = HelloWorld

scala> val two = new HelloWorld();
<console>:9: error: not enough arguments for constructor HelloWorld: (value1: String, value2: String)HelloWorld.
Unspecified value parameters value1, value2.
       val two = new HelloWorld();
                 ^

    主构造器的参数一般有四种:

// 1. 对象私有字段
class HelloWorld(value : String) {......}

// 2. 私有字段,私有getter和setter方法
class HelloWorld(private val/var value : String) {......}

// 3. 私有字段,公有的getter和setter方法
class HelloWorld(val/var value : String) {......}

// 私有字段,公有的Scala和JavaBean的getter和setter方法

// 如:
class HelloWorld private (val value1 : String, val value2 : String) {类成员}

    主构造器私有,只能通过辅助构造器构造对象。

    在Scala中,除主构造函数之外的构造函数都称为辅助构造器(或是从构造函数)。


5、辅助构造器

    Scala能够有任意多的辅助构造器;

    辅助构造器使用 this(…)的语法,在类中定义,所有辅助构造器名称为this;

    辅助构造器必须以一个主构造器或其他已定义的辅助构造器调用开始。

/**
 * @author lucl
 */
// 当通过private修饰后该类的主构造函数不可再被访问,如果希望创建该类的对象,
// 只能通过辅助构造函数,不能再new Teacher
class Teacher private() {
  println("This is primary constructor.")
  
  // 若属性被定义但是没有给予初始值的话,认为是抽象的成员,类必须声明为abstract的,
  // 这里使用占位符,即gender没有明确的值,只是标识这里需要有一个值,但val类型的则不可使用占位符
  var gender: String = _;
    
  def this(name : String, age : Int) {  // 构造器重载
    this;
    
  }
  
  def this (name : String, age : Int, gender : String) {  // 构造器重载
    this(name, age);
    
    this.gender = gender;
  }
  
  def info () {
    println(this gender);
  }
}

/**
 * 执行入口
 */
object Exec {
  def main(args : Array[String]) {
    val t = new Teacher("zhangsan", 20, "male");
    t.info;
  }
}


6、单例对象

    基于“纯OO”的理念,scala里没有static关键字的:一切皆对象! 

    在Scala中使用object关键字定义Singleton(单例)对象,Scala中不可以使用new再创建一个新的Singleton对象,此外和类定义不同的是,singleton对象不可以带参数,对象的构造器在该对象第一次被使用时调用。

    单例对象的成员直接通过单例对象名进行访问,其所有成员均为val类型的。

    单例对象的使用环境:

        作为存放工具函数或常量的地方;

        共享单个不可变实例;

        利用单个实例协调某个服务。

object HelloWorld {
    def main(args : Array[String]) {
        println("Hello World!");
    }
}

    这是一个最简单的Scala程序,HelloWorld 是一个Singleton对象,它包含一个main方法(可以支持命令行参数),和Java类似,Scala中任何Singleton对象,如果包含main方法,都可以作为应用的入口点

  

7、伴生对象:

    当一个单例对象存在同名类的时候,称为类的伴生对象(Companion object)。

    类和伴生对象可以互相访问私有属性,但必须存在同一个源文件中。

# 对应的scala文件名称为printargs.scala

package com.lucl.scala

/**
 * @author luchunli
 */
class HelloWorld {
  def say(f : (Int) => (Unit)) {
    f(HelloWorld.age);            // 可以访问伴生对象的私有属性
  }
}

object HelloWorld {
  val name : String = "zhangsan";
  private var age = 20;
  
  def sayHi (nage : Int) {
    println(name + " : " + age);
  }
  
  def main(args: Array[String]): Unit = {
    var hello = new HelloWorld;
    hello.say(sayHi);            // 将sayHi方法作为参数
  }
}

    注意,在Scala中不要求public类定义和文件同名,不过建议类名和文件同名。