zoukankan      html  css  js  c++  java
  • Scala对象

    面向对象

    Scala的面向对象思想和Java的面向思想和概念是一致的。

    Scala中语法和Java不同,补充了更多的功能。

    Scala包

    package 包名
    

    三大作用:

    • 区分相同名字的类
    • 当类很多的时候,可以很好的管理类
    • 控制访问范围

    包的命名

    只能包含数字、字母、下划线、小圆点,但不能用数字开头,也不要使用关键字。

    一般是小写字母 + 小圆点

    com.公司名.项目名.业务模块名

    包说明

    包对象

    在Scala中可以为每个包定义一个同名的包对象,定义在包对象的中的成员,作为其对应包下所有class 和 object 的共享变量,可以被直接访问。

    package object com {
        val shareValue= "share"
        def shareMethod() = {}
    }
    

    导包说明

    • 和Java一样,可以在顶部使用import导入,在这个文件中的所有类都可以使用
    • 局部导入,什么时候使用,什么时候导入。在其作用范围内都可以使用
    • 通配符导入 import java.util._
    • 给类起名 import java.util.{ArrayList => JL}
    • 导入相同包的多个类 import java.util.{HashSet, ArrayList}
    • 屏蔽类 import java.util.{ArrayList => _,_}
    • 导入包的绝对路径 import new_root_.java.util.ArrayListi

    类和对象

    类:可以看成一个模板

    对象:表示具体的事物

    定义类

    Scala中没有public,一个Scala中可以写多个类

    Scala语法中,类并不声明为public,所有这些类都具有公共可见性,即默认就是public

    一个Scala源文件可以包含多个类

    package chapter06
    
    import scala.beans.BeanProperty
    
    object Test03_Class {
      def main(args: Array[String]): Unit = {
        // 创建一个对象
        val student = new Student()
    
        // 不能通过以下的方式访问name属性,因为它是private
        println(student.age)
        println(student.sex)
    
        student.setSex("male")
        println(student.sex)
        
        student.age = 20
        println(student.getAge)
      }
    }
    
    // 定义一个类
    class Student{
      // 定义属性
      // 属性默认为public
      // 增加注解添加getter和setter
    
      private var name: String = "zihoo"
    //  @BeanProperty
    //  val age: Int = 18
    //
    //  val sex: String = "male"
    //  var nullValue: String = _
    
      @BeanProperty
      var age: Int = _
      @BeanProperty
      var sex: String = _
    }
    

    封装

    封装就是把抽象出的数据和数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作(成员方法),才能对数据进行操作。

    Scala中的public属性,底层实际为private,并通过get方法和set方法对其进行操作。所以Scala并不推荐将其属性设为private,再为其设置public的get和set方法的做法。

    但由于很多Java框架都利用反射调用get和set的方法,有时候为了和这些框架兼容,也会通过@BeanProperty注解为类实现get和set的方法。

    访问权限

    Scala中属性和方法的默认访问权限为public,但是Scala中无public关键字。

    private为私有权限,只有类的内部和伴生对象中可用。

    protected为受保护权限,Scala中受保护权限比Java中更严格,同类、子类可以访问,同包无法访问。

    private[包名] 增加包的访问权限,包名下的其它类也可以使用

    package chapter06
    
    object Test04_Access {
      def main(args: Array[String]): Unit = {
        // 创建对象
        val person: Person = new Person()
        // protected只能在子类或本类中可以访问
        // person.name
        println(person.age)
        println(person.sex)
        person.printInfo()
    
        val worker: Worker = new Worker()
        worker.printInfo()
      }
    }
    
    class Worker extends Person {
      override def printInfo(): Unit = {
        name = "Worker"
        age = 25
        sex = "female"
        println(s"Worker => {姓名:${name}, 性别:${sex},年龄:${age}}")
      }
    }
    

    方法

    就是定义在类中的函数

    def 方法名(参数列表) [: 返回值类型] = {
        	方法体
    }
    

    创建对象

    和Java类似

    val person: Person = new Person()
    

    当使用修饰符 val 后,表示常量,也就是不可更改的。所有当使用person = new Person() 是不被允许的。但是可以修改person的属性值 person.age = 12 ,这样是被允许的。

    构造器

    和 Java一样,Scala构造对象也需要调用构造方法,并且可以有任意多个构造方法。

    Scala的构造器包括:主构造器和辅助构造器

    class 类名(形参列表) {	// 主构造器
        // 类体
        def this(形参列表) {	// 辅助构造器
            
        }
        def this(形参列表) {	// 辅助构造器
            
        }
    }
    

    辅助构造器,函数的名称this,可以有多个,编译器通过参数的个数及类型来区分

    辅助构造方法不能直接构造对象,必须直接或者间接调用主构造方法

    构造器调用其他另外的构造器,要求被调用的构造器必须提前声明

    package chapter06
    
    object Test05_Constructor {
      def main(args: Array[String]): Unit = {
    
      }
    }
    
    // 定义一个类
    class Animal() {
      // 定义属性
      var name: String = _
      var age: Int = _
    
      println("1. 主构造方法调用")
      def this(name: String, age: Int){
        // 直接调用著构造器
        this()
        println("2. 辅助构造方法1被调用")
        this.name = name
        this.age = age
        println(s"name: ${name}, age:${age}")
    
      }
    
      def this(name: String) {
    
        this(name, 20)
        println("3. 辅助构造方法2被调用")
    
        
      }
    }
    

    构造器参数

    Scala类的主构造器函数的形参包括三种类型:未用任何修饰符、var修饰符、val修饰符

    • 未用任何修饰符,这个参数就是一个局部变量
    • var修饰符,作为类的成员属性使用,可修改
    • val修饰符,作为类的只读属性使用,不可修改
    package chapter06
    
    object Test06_ConstructorParams {
      def main(args: Array[String]): Unit = {
        val model = new ConstructorModel("zihoo", 21, 'M')
    
        model.age = 20
        // model.sex = 'W' 常量不可以修改
        println(s"model => {age: ${model.age}, sex: ${model.sex}")
      }
    }
    
    // 定义一个类
    class ConstructorModel(name: String, var age: Int, val sex:Char)
    

    继承和多态

    class 子类名 extends 父类名 {
        类体
    }
    

    子类继承父类的属性和方法

    scala是单继承

    package chapter06
    
    object Test07_Inherit {
      def main(args: Array[String]): Unit = {
        val student = new Test07Student("zihoo", 21)
        val student2 = new Test07Student("gazikel", 21, "20194077")
      }
    }
    
    // 定义一个父类
    class Test07Person {
      var name: String = _
      var age: Int = _
    
      println("1. 父类的主构造器调用")
    
      def this(name: String, age:Int) {
        this()
        println("2. 父类的辅助构造器调用")
        this.name = name
        this.age = age
      }
    
      def printInfo( ): Unit = {
        println(s"Person => {${name}, ${age}")
      }
    }
    
    // 定义子类
    class Test07Student(name: String, age: Int) extends Test07Person {
    
      var stuNo: String = _
    
    
      println("3. 子类的主构造器调用")
    
      def this(name: String, age:Int, stuNo:String) {
        this(name, age)
        println("4. 子类的辅助构造器调用")
        this.stuNo = stuNo
      }
    
      override def printInfo(): Unit = {
        println(s"Student => {${name}, ${age}, ${stuNo}")
      }
    
    
    }
    

    在Java中,属性是静态绑定的。

    而在Scala中,属性和方法都是动态绑定的。

    package chapter06
    
    object Test08_DynamicBind {
      def main(args: Array[String]): Unit = {
        val student: Test08Person = new Test08Student()
    
        println(student.name)
        student.hello()
      }
    }
    
    class Test08Person() {
      val name:String = "Person"
      def hello(): Unit = {
        println("Hello Person")
      }
    }
    
    class Test08Student extends Test08Person {
      override val name:String = "Student"
    
      override def hello(): Unit = {
        print("Hello Student")
      }
    }
    

    抽象类

    抽象属性和抽象方法

    • 定义抽象类 abstract class Person {} ,通过abstract关键字标记抽象类
    • 定义抽象属性 val | var name: String ,一个属性没有初始化,就是抽象属性
    • 定义抽象方法 def hello(): String ,只声明而没有实现的方法,就是抽象方法

    只要存在了抽象属性或抽象方法,那么这个类一定是抽象类。

    package chapter06
    
    object Test09_AbstractClass {
      def main(args: Array[String]): Unit = {
        
      }
    }
    
    // 定义一个抽象类
    abstract class Test09Person{
      // 非抽象
      val name: String = "Person"
      
      def eat(): Unit = {
        println("eat")
      }
      
      // 抽象
      var age: Int
      
      def sleep(): Unit
    }
    
    class Test09Student extends Test09Person {
      // 实现抽象类和方法
      var age: Int = 21
    
      def sleep(): Unit = {
        println("Student Sleep")
      }
    }
    

    匿名子类

    和Java一样,可以通过包含带有定义或重写代码块的方式创建一个匿名的子类

    package chapter06
    // 匿名子类
    object Test10_AnnoymousClass {
      def main(args: Array[String]): Unit = {
        val person: Test10Person = new Test10Person {
          override var name: String = "zihoo"
    
          override def eat(): Unit = println("person eat")
        }
    
        println(person.name)
        person.eat()
      }
    }
    
    // 定义一个抽象类
    abstract class Test10Person{
      var name: String
      def eat(): Unit
    }
    
    

    单例对象

    Scala语言是完全面向对象的语言,所以并没有静态的操作(即在Scala中没有静态的概念)。但是为了能够和Java语言交互(因为Java中有静态概念),就产生了一种特殊的对象来模拟类对象,该对象为单例对象。若单例对象名与类名一致,则称该单例对象这个类的伴生对象,这个类的所有“静态”内容都可以放置在它的伴生对象中声明

    单例对象语法

    object Person {
        val country: String = "China"
    }
    

    单例对象采用object关键字声明

    单例对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。

    单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。

    package chapter06
    
    object Test11_Object {
      def main(args: Array[String]): Unit = {
        val person: Test11Person = Test11Person.newPerson("zihoo", 21)
    
        // 使用apply
        val person2: Test11Person = Test11Person.apply("gazikel", 22)
    
        // 在Scala的底层,如果使用apply方法创建对象的实例,那么我们可以省区aplly调用方法名,如下。
        val person3: Test11Person = Test11Person("gazikel_apply", 23)
        person3.printInfo()
      }
    }
    
    // 构造方法私有化
    class Test11Person private(var name: String, var age: Int) {
      def printInfo(): Unit = {
        println(s"Person => {${name}, ${age}, ${Test11Person.school}}")
      }
    }
    
    object Test11Person {
      val school: String = "atguigu"
    
      // 定义一个创建类对象实例的方法
      def newPerson(name: String, age: Int): Test11Person = new Test11Person(name, age)
    
      def apply(name: String, age: Int): Test11Person = new Test11Person(name, age)
    }
    

    特质

    ​ Scala语言中,采用特质trait来代替接口的概念,也就是说,多个类具有相同的特质时,就可以将这个特质独立出来,采用关键字trait声明。

    ​ Scala中的trait中 既可以有抽象属性和方法,也可以有具体的属性和方法,一个类可以混入多个特质。这种感觉类似于Java中的抽象类。

    ​ Scala引入trait特质,第一可以替代Java的接口,第二个也是对单继承机制的一种补充。

    特质声明

    trait 特质名 {
        trait主体
    }
    

    特质基本语法

    一个类具有某种性质,就意味着这个类满足了这个特质的所有要素,所以在使用时,也采用了extends关键字,如果有多个特质或存在父类,那么采用with关键字进行连接。

    # 没有父类
    class 类名 extends 特质1 with 特质2 with 特质3
    # 有父类
    class 类名 extends 父类 with 特质1 with 特质2 with 特质3
    
    package chapter06
    
    object Test13_Trait {
      def main(args: Array[String]): Unit = {
        val student: Test13Student = new Test13Student()
        student.study()
        student.dating()
      }
    }
    
    class Test13Person{
      val name: String = "person"
      var age: Int = 21
    
      def sayHello(): Unit = {
        println("Hello" + name)
      }
    }
    
    // 定义一个特质
    trait Young {
      // 可以声明抽象或非抽象属性
      var age: Int
      val name: String = "young"
    
      def play(): Unit = {
        println("Young people is playing.")
      }
    
      def dating(): Unit
    }
    
    class Test13Student extends Test13Person with Young {
    
      // 重写冲突的属性
      override val name: String = "Student"
    
      override def dating(): Unit = {
        println(s"Student ${name} is dating.")
      }
    
      def study(): Unit = println(s"Student ${name} is studying")
    
      override def sayHello(): Unit = {
        super.sayHello()
        println(s"Hello from Student ${name}")
      }
    }
    

    特质的覆盖

    父类和叠加的特征是平等的。当有相同的方法或属性时,后面的特征会覆盖前面的特征。

    叠加顺序是从右到左。

    如果遇到两个特征继承自同一个特征,则父特征在最右边。

    super指的是此特征的叠加顺序的上一级。

    如果想让super为父类,则需要写为 super[类名]

    特征和抽象类的区别

    1.优先使用特质。一个类扩展多个特质是很方便的,但却只能扩展一个抽象类。

    2.如果你需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数,而特质不行。

    自身类型

    自身类型可实现依赖注入功能

    package chapter06
    
    object Test16_TraitSelfType {
      def main(args: Array[String]): Unit = {
        val register: RegisterUesr = new RegisterUesr("zihoo", "123456")
        register.insert()
      }
    }
    
    // 定义一个用户类
    class User(val name: String, val password: String)
    
    trait UserDao {
    
      // 自身属性
      _: User =>
    
      def insert(): Unit = {
        println(s"insert into db values(${name}, ${password})")
      }
    }
    
    class RegisterUesr(name: String, password: String) extends User(name, password) with UserDao {
    
    }
    

    扩展

    类型检查和转换

    obj.isInstanceOf[T]: 判断obj是不是T类型
    obj.asInstanceOf[T]: 判断obj强转成T类型
    classOf: 获取对象的类名
    

    枚举类和应用类

    枚举类:需要继承Enumeration

    应用类:需要继承App

    Type定义新类型

    使用type关键字可以定义新的数据类型名称,本质上就是类型的一个别名。

    object Test{
        def main(args: Array[String]): Unit = {
            type S = String
            var v: S = "abc"
            def test(): S = "xyz"
        }
    }
    
  • 相关阅读:
    Javascript继承,再谈
    RHEL7使用systemctl管理服务
    centos7进入单用户模式修改root密码
    IBM DS5020 管理口密码重置
    IBM小机拆镜像换盘
    HMC版本支持
    IBM产品系列和AIX系统版本
    AIX 6.1创建逻辑卷并挂载【smitty】
    AIX中的网络管理
    创建AIX克隆盘
  • 原文地址:https://www.cnblogs.com/Gazikel/p/15772573.html
Copyright © 2011-2022 走看看