(三)Scala面向对象编程

Scala面向对象编程

面向对象编程的三个特性:

  1. 封装
    1) 属性 / 字段 (数据)
    2)方法(对数据的操作)
  2. 继承
    涉及到父类 & 子类的关系;
    对父类中的属性、方法进行重写;
  3. 多态
    父类引用指向子类对象【抽象类其实就是多态的一种体现】

1.1. Scala中常用的类定义

  1. Scala中类的定义,可以用class也可以用object
  2. 如果在scala中需要有主入口main方法,只能定义为object【特殊情况,如果extends APP,就可以不用main方法】
  3. class 类1{} 为 object 类1{}的伴生类,object类1{} 为 class 类1{}的伴生对象
    具体文章参考:【 Scala中apply的应用
class 类名{
	//定义属性
	//定义方法
}
object 类名{
	//定义属性
	//定义方法
}
  • 特殊情况:如果extends App,就可以不用main方法
object AppTest extends App {
  println("不用main也可以输出")
  util.Properties.setProp("scala.time","true")  // 打印scala运行数据 ,输出结果:[total 225ms]
}

使用命令:scalac xxx.scala编译源码,生成.class文件;
使用命令:javap -p xxx,反编译class文件

import scala.beans.BeanProperty

class User{
  @BeanProperty val name = "Scala"
  val age = 18
  var address = "成都"
  private val money = 10000L
  def eat() = {
    println(s"$name : $age")
  }
  def printMoney() = {
    println(s"money = ${money}")
  }
}
--------------反编译class文件后,格式如下------------------

public class com.maggie.scalaDemo.User {
  private final java.lang.String name;
  private final int age;
  private java.lang.String address;
  private final long money;
  public java.lang.String name();      // 相当于getName()方法
  public int age();
  public java.lang.String address();
  public void address_$eq(java.lang.String);  // var修饰的变量,还多了address_$eq()方法,相当于setAddress()方法
  private long money();
  public void eat();
  public void printMoney();                // printMoney()方法
  public java.lang.String getName();         // @BeanProperty修饰的,就能看得setter和getter方法
  public com.maggie.scalaDemoUser();     // User 的无参构造器
}

--------------调用User对象---------------------
object UserTest{
  def main(args: Array[String]): Unit = {
    val user = new User()      // 实例化了一个User对象
    // user.name = "Maggie"   // 会报错,val定义的变量,不允许修改
    user.address = "chengdu"
    println("user.address = " + user.address)     // 输出结果:user.address = chengdu
    user.address_$eq("成都市")
    println("user.address = " + user.address)     // 输出结果:user.address = 成都市
    //如果想获取到money,只能通过printMoney()方法
    user.printMoney()                           // 输出结果:money = 10000                 
  }
}

1.2. scala主从构造器

  • 主构造器(一般只有一个)

    1)如果定义的Person类不带属性,则默认生成无参构造器
    2)无参构造器不一定是主构造器;
    3)主构造器中的参数个数需要和主构造器属性个数&类型一致

  • 附属构造器

    1)可以定义多个附属构造器
    2)辅助构造器的名称必须为 this;
    3)每个辅助构造器必须以主构造器或其他的辅助构造器的调用开始。
    4)如果是class Person(class : 自定义类) 则可以添加无参构造器;
    如果是class Person(val name:String)这种,则无法添加无参构造器

class Person(val name:String, val age:Int){
  println("功能类似于Java中的静态代码块 static{}, class Person enter")
  var gender:String = _
  // 1)辅助构造器的名称必须为 this;
  def this(name:String, age:Int, gender:String) ={
    // 该类有个默认主构造器:Person(name:String,age:int)
    // 2)每个辅助构造器必须以主构造器或其他的辅助构造器的调用开始。
    this(name, age)
    this.gender = gender
  }
  println("class Person over")
}
// 调用Person类
object PersonTest{
  def main(args: Array[String]): Unit = {
    val person = new Person("张三" , 21)
    println(person.name + ":" + person.age)    // 调用的时候才输出
  }
}
/**
 * ======输出结果(顺序--从上到下执行,调用类,最后执行构造器/方法中的输出)====:
 * 功能类似于Java中的静态代码块 static{}, class Person enter
 * class Person over
 * 张三:21
 */
----------Person.class 反编译后:javap -p .\Person.class----------
public class com.maggie.scalaDemo.Person {
  private final java.lang.String name;
  private final int age;
  private java.lang.String gender;
  public static void main(java.lang.String[]);
  public java.lang.String name();
  public void gender_$eq(java.lang.String);
  public com.maggie.scalaDemo.Person(java.lang.String, int);     // 主构造器,如果定义的Person类不带属性,则默认生成无参构造器
  public com.maggie.scalaDemo.Person(java.lang.String, int, java.lang.String);  // 附属构造器
}

// 参看Scala中的SparkContext类

1.3. Scala中方法重写override

  • 重写父类中的val属性或者方法,使用override关键字
// 父类Person
class Person(val name:String, val age:Int) {
  println("class Person enter......")
  var gender: String = "male"
  val address : String = "成都"
  def this(name: String, age: Int, gender: String) = {
    this(name, age)
    this.gender = gender
    println("我是Person类中3个参数的构造方法")
  }
  println("class Person  ......over")
}

// 子类Student
class Student(name:String, age:Int, val major:String) extends Person(name,age){
  println("class Student enter......")
  override def toString: String = name + "---" + age + "---" + major    // [override重写了Person中的toString方法]
  // override var gender = "female"   或者  override val gender = "female"   【var修饰的变量不能被重写,均报错】
  override val address = "成都市"       // 子类重写父类属性
  println("class Student ......over")
}

// 调用Student类
object StudentTest{
  def main(args: Array[String]): Unit = {
    val stu = new Student("张三" , 21, "Scala")
    println(stu.toString)          // 【(1)Student中重写toString方法前后输出结果不一致】
    println(stu.gender)            // 【Student中var修饰的变量不能被重写,均报错】
    println(stu.address)	      // 【Student中重写address属性前后输出结果不一致】
  }
}
/**
 * ======输出结果(--从上到下执行,调用父类,再调用子类,最后执行构造器/方法中的输出)====:
 * class Person enter......
 * class Person ......over
 * class Student enter......
 * class Student ......over
 * com.maggie.scalaDemo.Student@71c7db30  【(1)Student中重写toString方法前输出结果】
 * 张三---21---Scala                                                 【(1)Student中重写toString方法后输出结果】
 * male
 * 成都 【重写前输出结果】     成都市 【重写后输出结果】
 */

1.4. Scala抽象类abstract & extends &override

  • 抽象类中有一个或者多个方法没有完整的定义
  • 抽象类中,属性也可以申明为抽象字段
  • 抽象类是不能直接被实例化,可以通过子类去实例化(extends)

1)抽象属性可以写override也可以不写override,都对抽象属性进行重写
2)抽象类中的属性如果已经赋初始值中,子类重写属性的时候,必须要写override关键字, 否则报错

// 定义的抽象类
abstract class AbstractClass{
  def speak()
  val name:String
  val address:String
  val test:String = "test"
}

// 实现抽象类,使用关键字extends,重写方法/属性,使用关键字override
class SubClass extends AbstractClass{
  override def speak(): Unit = println("我是实现的子类重写的方法。。")
  override val name: String = "我是SubClass"
  val address:String = "成都市"      // 抽象属性可以写override也可以不写override,都对抽象属性进行重写
  override val test:String = "newTest1" // 必须要写override关键字, 否则报错
}

// 测试抽象类子类
object AbstractClassTest {
  def main(args: Array[String]): Unit = {
    println("---------方法一:子类继承抽象类---------")
    val subclass = new SubClass
    subclass.speak()
    println(subclass.name)
    println(subclass.address)
    println(subclass.test)
    println("---------方法二:匿名子类---------")
    val abStr = new AbstractClass {
      override def speak(): Unit = println("我是匿名子类重写的方法。。")
      override val name: String = "我是abStr"
      val address:String = "四川省"      // 抽象属性可以写override也可以不写override,都对抽象属性进行重写
      override val test:String = "newTest2" // 必须要写override关键字, 否则报错
    }
    abStr.speak()
    println(abStr.name)
    println(abStr.address)
    println(abStr.test)
  }
}

1.5. Scala中packge object

  • Scala的import还支持导包时候取别名

    • import com.gargantua.{HomeWork => HW}
  • 当Scala要调用Java API,而Scala的语法无能识别Java的类型,使用隐式转换需要导入 【scala.collection.JavaConverters._ 】再使用 asScala 转为scala的集合

import scala.collection.JavaConverters._ 

List list = new ArrayList()
for (e <- list.asScala) {
    // ...
}
  • 在当前包下可以唯一创建一个类名和包名相同的 packge object
  • 对于使用 packge object 中的方法,可以不用导包
package com

package object Person{
	// 使用 packge object 中的方法,可以不用导包
}

1.6. Scala中type关键字

  • Scala 使用 classOf() 返回运行时类型
  • 可以使用 type 关键字定义新的数据类型名称 (换了个名字)
type S = String   // 重写定义了一个S类型,为String重命名为S
val str:S = ""

1.7. Scala多态

  • 父类引用指向子类对象
  • val student = new Person()

1.8. Scala接口Trial

  • Scala没有interface接口,通过定义trait实现接口(javap 命令解析trait发现就是interface)
  • 继承/实现 ,都是用extends,多个接口放在with 后面
class Dog extends Animal with MyLogging with MyException {
    // 使用需要注意 Animal\MyLogging\MyException的顺序
    // super.method 只会匹配到最后一个with父类中的方法
    // super[MyLogging].method 可以指定特定父类 
} 

1.9. Scala泛型

泛型在Scala和Java中类似,用于类或者方法用于指定任意类型 或者一种类型的参数,参数在使用的时候才会被确定,泛型可以有效的增强程序的灵活性,使用泛型的目的是可以使得类或者方法具有更高的通用性,或者作为一种规范。
调用的时候指定类型即可。 其中的T* 表示的可变参数

  • 泛型的规则:
    • 1)泛型的上边界和下边界
      • 上边界(上限): 表示泛型的类型必须是 某种类型的子类,表示为 <:
      • 下边界(下限):表示泛型的类型必须是 某种类型的父类,表示为 >:
        【下限其实没有做实际的控制,与没有限制一样】
    • 2)协变和逆变
      • 协变: 在类型参数的前面加上一个 +
      • 逆变: 在类型参数前面加上一个 -

1.10. Ordering & Ordered(排序)

  • Scala中用于比较的两个类:Ordered、Ordering
    • Ordered 实现了java.lang.Comparable接口,对Comparable进行了扩展,更灵活,用气量更方便
    • Ordering 实现了java的 Comparator接口,同时对Comparator进行了扩展

Ordering : trait Ordering[T] extends Comparator[T]
Ordered : trait Ordered[T] extends java.lang.Comparable[T]

Comparator : public int compare(Obj o1, Obj o2)
Comparable : public int compareTo(Obj obj)

  • <% 视图界定
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值