Scala面向对象1

简介: Scala面向对象1

1 类

scala是支持面向对象的,也有类和对象的概念。

1.1 创建类和对象


  • 使用class关键字来定义类
  • 使用var/val来定义成员变量
  • 使用def来定义成员方法
  • 使用new来创建一个实例对象

示例1:

  1. 定义一个Customer类,该类包含以下成员:
成员变量
姓名(例如:张三、李四)
性别(例如:男、女)
注册时间(不可修改)(2010/03/12)
成员方法
sayHi(消息)
  1. 定义好类之后,创建该类的对象。并给该对象赋值,并打印对象中的成员,调用成员方法。

步骤

  1. 定义一个Customer类,并添加成员变量/成员方法
  2. 添加一个main方法,并创建Customer类的对象,并给对象赋值,打印对象中的成员,调用成员方法

scala代码:

class Customer {
  var name:String = _
  var sex:String = _
  val registerDate:Date = new Date
  def sayHi(msg:String) = {
    println(msg)
  }
}
object Main {
  def main(args: Array[String]): Unit = {
    val customer = new Customer
    customer.name = "张三"
    customer.sex = "男"
    println(s"姓名: ${customer.name}, 性别:${customer.sex}, 注册时间: ${customer.registerDate}")
    customer.sayHi("你好!")
  }
}
  1. var name:String = _,_表示使用默认值进行初始化

例如:String类型默认值是null,Int类型默认值是0,Boolean类型默认值是false…

  1. val变量不能使用_来进行初始化,因为val是不可变的,所以必须手动指定一个默认值
  2. main方法必须要放在一个scala的object(单例对象)中才能执行

1.2 getter/setter


问题1:

上述的案例,创建出来一个Customer实例,就可以给name、sex这些字段进行赋值、并可以获取它们的值。这是否意味着这些字段默认都是public的呢?

为了验证上述问题,我们需要反编译scala编译出来的class文件,看一看最终编译器出来的字节码是什么样的。

使用jd-gui工具反编译Customer类

使用jd-gui反编译Main类

问题2:

是否能够生成类似于Java的getter/setter方法呢?

可以,在字段上加上@BeanProperty就可以了。

  @BeanProperty
  var name:String = _             // 姓名
  @BeanProperty
  val registerDate = new Date()   // 注册时间

通过查看反编译的代码,scalac编译器已经自动帮助我们添加了Java的getter/setter

  1. scala会自动为成员变量生成scala语言的getter/setter
  2. scala的getter为字段名(),setter为字段名_=()
  3. 要生成Java的getter/setter,可以在成员变量上加一个@BeanProperty注解,这样将来去调用一些Java库的时候很有用

1.3 类的构造器


  • 主构造器
    主构造器是写在类后面,例如:
class 类名(var/val 参数名:类型 = 默认值, var/val 参数名:类型 = 默认值){
    // 构造代码块
}

辅助构造器

辅助构造器,使用this来定义,例如:

def this(参数名:类型, 参数名:类型) {
    ...
}

示例1:定义主构造器

class Student(_name:String, _age:Int) {
  var name:String = _
  var age:Int = _
  // 构造器的代码可以直接写在类中
  name = _name
  age = _age
}

示例2:简化定义主构造器

// 在主构造器中,可以直接定义成员变量
class Student(val name:String, val age:Int)

示例3:定义辅助构造器

class Student(val name:String, val age:Int) {
  // 定义一个参数的辅助构造器
  def this(name:String) {
    // 第一行必须调用主构造器、其他辅助构造器或者super父类的构造器
    this(name, 20)
  }
  def this(age:Int) {
    this("某某某", age)
  }
}
  1. 主构造器直接在类名后面定义
  2. 主构造器中的参数列表会自动定义为私有的成员变量
  3. 一般在主构造器中直接使用val/var定义成员变量,这样看起来会更简洁
  4. 在辅助构造器中必须调用其他构造器(主构造器、其他辅助构造器)

2 单例对象

scala要比Java更加面向对象,所以,scala中是没有Java中的静态成员的。如果将来我们需要用到static变量、static方法,就要用到scala中的单例对象——object。可以把object理解为全是包含静态字段、静态方法的class,object本质上也是一个class。

2.1 定义object


定义单例对象和定义类很像,就是把class换成object

示例:定义一个工具类,用来格式化日期时间

object DateUtils {
  // 在object中定义的成员变量,相当于Java中定义一个静态变量
  // 定义一个SimpleDateFormat日期时间格式化对象
  val simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm")
  // 构造代码
  println("构造代码")
  // 相当于Java中定义一个静态方法
  def format(date:Date) = simpleDateFormat.format(date)
  // main是一个静态方法,所以必须要写在object中
  def main(args: Array[String]): Unit = {
    println { DateUtils.format(new Date()) };
  }
}
  1. 使用object 单例对象名定义一个单例对象,可以用object作为工具类或者存放常量
  2. 在单例对象中定义的变量,类似于Java中的static成员变量
  3. 在单例对象中定义的方法,类似于Java中的static方法
  1. object单例对象的构造代码可以直接写在花括号中
  2. 调用单例对象的方法,直接使用单例对象名.方法名,访问单例对象的成员变量也是使用单例对象名.变量名
  3. 单例对象只能有一个无参的主构造器,不能添加其他参数

2.2 伴生对象

在Java中,经常会有一些类,同时有实例成员又有静态成员。例如:

public class Generals {
    private static String armsName = "青龙偃月刀";
    public void toWar() {
        //打仗
        System.out.println("武将拿着"+ armsName +", 上阵杀敌!");
    }
    public static void main(String[] args) {
        new Generals().toWar();
    }
}

在scala中,要实现类似的效果,可以使用伴生对象来实现。

1 定义伴生对象

一个class和object具有同样的名字。这个object称为伴生对象,这个class称为伴生类

  • 伴生对象必须要和伴生类一样的名字
  • 伴生对象和伴生类在同一个scala源文件中
  • 伴生对象和伴生类可以互相访问private属性

示例

需求

  • 编写一个Generals类,有一个toWar方法,打印
武将拿着**武器, 上阵杀敌!   //注意: **表示武器的名字.
  • 编写一个Generals伴生对象,定义一个私有变量,用于保存武器名称.
  • 创建Generals对象,调用toWar方法

参考代码

//案例: 演示Scala中的伴生对象
object ClassDemo12 {
  //1. 定义一个类Generals, 作为一个伴生类.
  class Generals {    //这里写的都是非静态成员.
    //2. 定义一个toWar()方法, 输出一句话, 格式为"武将拿着**武器, 上阵杀敌!"
    def toWar() = println(s"武将拿着${Generals.armsName}武器, 上阵杀敌!")
  }
  //3. 定义一个伴生对象, 用来保存"武将的武器".
  object Generals {   //这里写的都是静态成员.
    private var armsName = "青龙偃月刀"
  }
  //定义main方法, 作为程序的主入口
  def main(args: Array[String]): Unit = {
    //4. 创建Generals类的对象.
    val g = new Generals
    //5. 调用Generals类中的toWar方法
    g.toWar()
  }
}
  1. 伴生类和伴生对象的名字必须是一样的
  2. 伴生类和伴生对象需要在一个scala源文件中
  3. 伴生类和伴生对象可以互相访问private的属性

2.3 apply方法


我们之前使用过这种方式来创建一个Array对象。

// 创建一个Array对象
val a = Array(1,2,3,4)

这种写法非常简便,不需要再写一个new,然后敲一个空格,再写类名。如何直接使用类名来创建对象呢?

查看scala源代码:

答案就是:实现伴生对象的apply方法

伴生对象的apply方法用来快速地创建一个伴生类的对象。

示例1:

class Person(var name:String, var age:Int) {
  override def toString = s"Person($name, $age)"
}
object Person {
  // 实现apply方法
  // 返回的是伴生类的对象
  def apply(name:String, age:Int): Person = new Person(name, age)
  // apply方法支持重载
  def apply(name:String):Person = new Person(name, 20)
  def apply(age:Int):Person = new Person("某某某", age)
  def apply():Person = new Person("某某某", 20)
}
object Main2 {
  def main(args: Array[String]): Unit = {
    val p1 = Person("张三", 20)
    val p2 = Person("李四")
    val p3 = Person(100)
    val p4 = Person()
    println(p1)
    println(p2)
    println(p3)
    println(p4)
  }
}
  1. 当遇到类名(参数1, 参数2...)会自动调用apply方法,在apply方法中来创建对象
  2. 定义apply时,如果参数列表是空,也不能省略括号(),否则引用的是伴生对象

2.4 main方法

scala和Java一样,如果要运行一个程序,必须有一个main方法。而在Java中main方法是静态的,而在scala中没有静态方法。在scala中,这个main方法必须放在一个object中。

示例1:

object Main5 {
  def main(args:Array[String]) = {
    println("hello, scala")
  }
}

也可以继承自App Trait(特质),然后将需要编写在main方法中的代码,写在object的构造方法体内。

示例2:

object Main5 extends App {
  println("hello, scala")
}


目录
打赏
0
0
0
0
109
分享
相关文章
Scala:面向对象、Object、抽象类、内部类、特质Trait(二)
Scala:面向对象、Object、抽象类、内部类、特质Trait(二)
111 0
|
9月前
|
Scala面向对象练习题34道
Scala面向对象练习题34道
152 0
Scala面向对象3
Scala面向对象3
49 1
Scala面向对象4
Scala面向对象4
69 0
Scala学习三-面向对象
前面我们已经学习了特质类似接口,其可以被继承,同时如果需要继承多个特质的话,则需要使用extends…with…进行继承。其类似java中的接口和抽象方法的结合体,但又比java中的其要强大,因为其可以定义抽象字段和普通字段、抽象方法和普通方法。而在java中接口中可以定义常量,不能定义变量。同时特质还可以继承class类,而在java中接口通常是用来实现的。 Object继承trait
151 0
Scala学习三-面向对象
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等