【Scala】04 对象特性Part1

时间:2021-07-12
本文章向大家介绍【Scala】04 对象特性Part1,主要包括【Scala】04 对象特性Part1使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

1、声明式包管理:

一个Scala文件可以声明N个包

包的意义和Java的包管理是一样的

同样也需要import导入资源声明

package pkgA {
  import com.oracle.nio.BufferSecretsPermission

  object PackageOuter {
    var out : String = "OUTER"

  }

  package pkgB {
    package pkgC {

      object PackageInner {
        def main(args: Array[String]): Unit = {
          println(PackageOuter.out)
          PackageOuter.out = "INNER"
          println(PackageOuter.out)
        }
      }
    }
  }
}

package pkgE {

  package pkgG {

    import pkgA.PackageOuter

    object gg {
      def main(args: Array[String]): Unit = {
        println (PackageOuter.out)
        PackageOuter.out = "INNER"
        println (PackageOuter.out)
      }
  }
  }
}

2、包对象

Scala可以为每一个包定义一个同名的对象,包对象中定义的成员,可以被这个包下所有的Class和Object访问

【使用Java原始风格的包管理,包对象一般定义在包下的package.scala文件中,包的对象名和包名一致】

在其他Scala文件中可以直接访问:

package cn.dzz

object Main {

  def main(args: Array[String]): Unit = {
    // 在包下面可以直接访问
    commonMethod()
    println(commonValue)
  }

}

如果Package文件是复合的,也是一样

package cn
// 定义dzz包对象
package object dzz {
  val commonValue = "1001001"

  def commonMethod() = {
    println(commonValue)
  }
}


package ccc {
  import cn.dzz._
  object ddd {
    def main(args: Array[String]): Unit = {
      commonMethod()
      println(commonValue)
    }
  }
}

3、导包区别:

/**
 * 导入包说明
 * 1、可以和Java一样在顶部使用import导入,这个文件中所有导入的类都可以使用
 * 2、局部导入,什么时候调用,什么时候导入,在这个调用的作用域内都可以使用
 * 3、Java导入所有的通配符是*,Scala导入所有通配符是_
 * 4、给类起名 import.java.util.{ArrayList => AL}
 * 5、导入相同包的多个类 import java.util.{HashSet, ArrayList}
 * 6、排除导入的类 import java.util.{ArrayList => _,_}
 * 7、完整名称书写,Java语法 new java.lang.String Scala语法 new _root_.java.util.HashMap
 *
 * 三个默认导入的包资源
 * import.java.lang._
 * import.scala._
 * import.scala.Predef._
 *
 */

4、类成员的定义:

// 定义多个类
class Class1 {
  var name = "alice" // 同样属性也可以有修饰符 不加修饰符默认表示public


  private var age = 18 // 表示私有的

  @BeanProperty // 创建和Java一样的Getter&Setter, 该注解对private修饰是错误的?
  protected var gender = true

  // 设定初始值
  var property1:Int = _ // 值放的是下划线,但是必须要声明变量的类型,Scala需要根据类型来推断初始值
  var property2:String = _ // Int初始0 String初始null
}

class Class2 {

}

5、封装和访问权限

package cn

object HelloScala {
  def main(args: Array[String]): Unit = {
    val superClass = new SuperClass
    //  println(superClass.property1) // property1不能被访问, 是被标注为private受保护的
    //  println(superClass.property2) // property2不能被访问, 是被标注为protected受保护的
    println(superClass.property3)
    println(superClass.property4)

    superClass.printInfo()

    val subClass = new SubClass
    subClass.printInfo()

  }
}
/**
 * Java 访问权限 public protected (default) private
 * 1、public 可以被公开访问
 * 2、protected 仅限类和继承的子类访问
 * 3、(default) 类和所调用的访问
 * 4、private 只能在类的内部访问
 *
 * Scala 访问权限 (default -> public) protected private
 * 1、Scala默认public 公开访问
 * 2、protected 受保护权限,比Java更严格,同类,子类可以访问,同包无法访问
 * 3、private[包名称] 增加访问权限,包名下的其他类也可以使用
 */
class SuperClass { // 上级类
  private var property1 : String = "223112312"
  protected var property2 : String = "zhangSan"
  var property3 : Boolean = true
  private [cn] var property4 : Int = 24

  def printInfo() = {
    println(s"cn.SuperClass p1 = $property1, p2 = $property2, p3 = $property3, p4 = $property4")
  }


}


class SubClass extends SuperClass {



  // 重写父类方法
  override def printInfo(): Unit = {
    // 调用父类方法
//    super.printInfo()
    // 修饰为 private 的 property1 不能被这个SubClass子类访问到
//    println(s"property1 : $property1") // 这样写报错

    property2 = "12"
    property3 = false
    property4 = 100
    super.printInfo()
  }


}

6、构造器 Constructor

/**
 *  // Scala和Java一样拥有主构造器和辅助构造器
 *
 *  class 类名(形参列表) { // 主构造器
 *    // 类体
 *    def this(形参列表) {
 *      // 辅助构造器1
 *    }
 *    def this(形参列表) {
 *      // 辅助构造器2
 *    }
 *    // 可以有多个辅助构造器 ...
 *  }
 *
 *  1、多个构造器通过重载的形式来进行区分
 *  2、辅助构造器不直接构建对象,必须取调用主构造器实现
 *  3、构造器调用其他另外的构造器,必须 提前声明被调用的构造器
 */

class Student() {
  var name : String = _
  var age : Int = _
  var gender : Boolean = _

  println("主构造方法调用")

  def this(name : String) {
    this() // 辅助构造器必须要先调用主构造器
    println("辅助构造器1被调用")
    this.name = name
    println(s"name : ${this.name} age : $age gender : $gender")
  }

  def this(name : String, age : Int) {
    this(name)
    println("辅助构造器2被调用")
    this.age = age
    println(s"name : ${this.name} age : $age gender : $gender")
  }

  def this(name : String, age : Int, gender : Boolean) {
    this(name, age)
    println("辅助构造器2被调用")
    this.gender = gender
    println(s"name : ${this.name} age : $age gender : $gender")
  }

  def Student(): Unit = {
    println("对象一般方法被调用")
  }

}

调用时:

object HelloScala {
  def main(args: Array[String]): Unit = {

    val student = new Student
    student.Student()
  }
}

关于构造器参数:

package cn

object HelloScala {
  def main(args: Array[String]): Unit = {
    val student = new Student("张三", 24, true)
    // 调用打印的时候可以发现这个模板语法就不能打印student.name了 因为name不是成员属性
    //    println(s"student = {name : ${student.name}, age : ${student.age}, gender : ${student.gender}}")
    // student.gender = false // gender 设定为val常量,只允许在构造器调用时赋值一次


  }
}

/**
 * 构造器参数问题
 * 参数包括三种类型
 * 1、无任何修饰 该参数是一个局部变量
 * 2、Var修饰 作为类的成员属性使用, 可以写值
 * 3、Val修饰 作为类的成员属性使用, 只读属性
 *
 */
class Student
(
name : String, // 局部变量
var age : Int, // 成员属性,可以写值
val gender : Boolean // 成员属性,只读属性
) 

7、继承关系

package cn

object HelloScala {
  def main(args: Array[String]): Unit = {
    val son1 = new Son("zhangSan", 18)
    val son2 = new Son("zhangSan", 18, "1003001")
  }
}

/**
 * 继承和多态
 * class 子类名 extends 父类名 { 类体 }
 * 子类继承父类没有访问限制的属性和方法
 * 继承和Java一样,是单继承的
 */
class Father() {
  var name : String = _
  var age : Int = _

  println("Father 主构造器调用!")

  def this(name : String, age : Int) {
    this()
    println("Father 辅助构造器调用!")
    this.name = name
    this.age = age
  }

  def printInfo(): Unit = {
    println(s"Father => { name = $name, age = $age }")
  }
}
class Son(name : String, age : Int) extends Father {
  var no: String = _
  def this (name : String, age : Int, no : String) {
    this(name, age)
    println("Son 辅助构造器调用!")
    this.no = no
  }

  println("Son 主构造器调用!")

  override def printInfo(): Unit = {
    println(s"Son => { name = $name, age = $age }")
  }
}

如果继承的父类构造器声明的是辅助构造器参数,那么还会调用辅助构造参数

class Son(name : String, age : Int) extends Father(name, age) 

8、多态

package cn

object HelloScala {
  def main(args: Array[String]): Unit = {
    // Scala 进行多态和Java的表达是一样的,需要强制声明引用类型
    val daughter : Mather = new Daughter // 父类引用 指向 子类实例
    daughter.sayHello()
  }
}

// 多态实现
class Mather {
  val name : String = "Mather"
  def sayHello() : Unit = println(s"Hello Mather $name")
}
class Daughter extends Mather {
  override val name : String = "Daughter"
  override def sayHello() : Unit = println(s"Hello Daughter $name")
}

9、抽象类:

package cn

object HelloScala {
  def main(args: Array[String]): Unit = {
    val s : Common = new Specific
    s.method1()
  }
}

/**
 * 抽象类
 */
abstract class Common {
  var property1 : String // 没有赋值或者初始值,这个属性也算抽象
  def method1() : Unit // 抽象方法
}

class Specific extends Common {
  override var property1 : String = "123456" // 没有赋值或者初始值,这个属性也算抽象
  override def method1() : Unit = {
    // 抽象方法的实现
    println("Common abstract Implement !")
  }
}

10、匿名子类,匿名实现类

package cn

object HelloScala {
  def main(args: Array[String]): Unit = {
    val s : Common = new Common {
      override val property: String = "asdasd"

      override def method(): Unit = {
        println("method Implement By anonymous Class!!!")
      }
    }
    
    s.method()
  }
}

/**
 * 匿名子类
 *
 */
abstract class Common {
  val property : String
  def method() : Unit
}

这张图可以直接看懂,Scala是做了一个动静分离的处理

Object 就可以表示一个Static修饰

11、特质(接口)

package cn

object HelloScala {
  def main(args: Array[String]): Unit = {
    val spec : Spec = new Spec
    spec.sayHello()
    spec.dating()
  }
}



class Specific {
  val p1 : String = "initVal"
  var p2 : Int = _

  def sayHello(): Unit = println("asdasdas")
}

// 这个类很奇怪,必须要继承某一个类之后才能实现特质
class Spec extends Specific with Common {
  val p1: String
  var p2: Int
  override var age: Int = _

  override def dating(): Unit = {
    println("asdasd")
  }


}


/**
 * 特质 TRAIT
 * 这个东西使用来代替Java的接口
 * 多个类具有相同的特质,可以抽取特质独立于类来创建,用关键字trait声明
 * 一个普通类可以混合多个特质
 * trait可以抽象方法和属性,也可以有具体的实现
 */

trait Common {
  var age : Int
  val name : String = "young"

  def play() : Unit = {
    println("young man always struggle")
  }
  def dating() : Unit
}

动态混入:

就是直接实现接口完成:

package cn

object HelloScala {
  def main(args: Array[String]): Unit = {
    // 动态混入 注意这里变量不能指定了
    val specificWithCommon = new Specific with Common {
      override var age: Int = _
      override def dating(): Unit = {
        println("dating impl")
      }
    }
    specificWithCommon.sayHello()
    specificWithCommon.dating()
    println(specificWithCommon.age)
  }
}

class Specific {
  val p1 : String = "initVal"
  var p2 : Int = _

  def sayHello(): Unit = println("asdasdas")
}
/**
 * 特质 TRAIT
 * 这个东西使用来代替Java的接口
 * 多个类具有相同的特质,可以抽取特质独立于类来创建,用关键字trait声明
 * 一个普通类可以混合多个特质
 * trait可以抽象方法和属性,也可以有具体的实现
 */

trait Common {
  var age : Int
  val name : String = "young"

  def play() : Unit = {
    println("young man always struggle")
  }
  def dating() : Unit
}

原文地址:https://www.cnblogs.com/mindzone/p/15000206.html