scala之面象对象之中级

1、scala包

1.1、基本语法

package 包名

1.2、包的作用(和java一样)

  1. 区分相同名字的类
  2. 当类很多时,可以很好的管理类
  3. 控制访问范围
  4. 可以对类的功能进行扩展

1.3、命名规则

只能包含数字、字母、下划线、小圆点.,但不能用数字开头, 也不要使用关键字。
demo.class.exec1  //错误 , 因为class是关键字
demo.12a    // 错误,因为不能以数字开头

1.4、自动引入的常用包

  • java.lang.*
  • scala包
  • predef包

1.5、注意事项

① scala在一个文件中可以创建多个包以及给各个包创建类,trait和object

//1. package com.nuc{}  表示我们创建了包 com.nuc ,在{}中
//   我们可以继续写它的子包 scala //com.nuc.scala, 还可以写类,特质trait,还可以写object
//2. 即sacla支持,在一个文件中,可以同时创建多个包,以及给各个包创建类,trait和object

package com.nuc {  //包 com.nuc
  package scala { //包 com.nuc.scala

    class Person { // 表示在 com.nuc.scala下创建类 Person
      val name = "Nick"

      def play(message: String): Unit = {
        println(this.name + " " + message)
      }
    }
    object Test100 { //表示在 com.nuc.scala 创建object Test
      def main(args: Array[String]): Unit = {
        println("ok")
      }
    }
  }
}
//1. package com.nuc{}  表示我们创建了包 com.nuc ,在{}中
//   我们可以继续写它的子包 scala //com.nuc.scala, 还可以写类,特质trait,还可以写object
//2. 即sacla支持,在一个文件中,可以同时创建多个包,以及给各个包创建类,trait和object

package com.nuc {  //包 com.nuc

  class User { // 在com.nuc包下创建个 User类
  }

  package scala2 { // 创建包 com.nuc.scala2
  class User { // 在com.nuc.scala2 包下创建个 User类
  }
  }

  package scala { //包 com.nuc.scala

    class Person { // 表示在 com.nuc.scala下创建类 Person
      val name = "Nick"

      def play(message: String): Unit = {
        println(this.name + " " + message)
      }
    }
    object Test100 { //表示在 com.nuc.scala 创建object Test
      def main(args: Array[String]): Unit = {
        println("ok")
      }
    }
  }

}

②作用域:可以直接向上访问。即: Scala中子包中直接访问父包中的内容, 大括号体现作用域。(提示:Java中子包使用父包的类,需要import)。在子包和父包 类重名时,默认采用就近原则,如果希望指定使用某个类,则带上包名即可

package com.nuc {  //包 com.nuc

  class User { // 在com.nuc包下创建个 User类

  }

  package scala2 { // 创建包 com.nuc.scala2
  class User { // 在com.nuc.scala2 包下创建个 User类
  }
  }

  package scala { 

    class Person { 
      val name = "Nick"

      def play(message: String): Unit = {
        println(this.name + " " + message)
      }
    }

    class User {

    }

    object Test100 { 
      def main(args: Array[String]): Unit = {
        println("ok")
        //我们可以直接使用父包的内容
        //1.如果有同名的类,则采用就近原则来使用内容(比如包)
        //2.如果就是要使用父包的类,则指定路径即可
        val user = new User
        println("user=" + user) //
        val user2 = new com.nuc.User()
        println("user2" + user2)

      }
    }
  }

}

③父包要访问子包的内容时,需要import对应的类等

package com.nuc {  //包 com.nuc

  class User { // 在com.nuc包下创建个 User类
    def sayHello(): Unit = {
      //想使用 com.nuc.scala2包下的 Monster
      import com.nuc.scala2.Monster
      val monster = new Monster()
    }
  }

  package scala2 { // 创建包 com.nuc.scala2
  class User { // 在com.nuc.scala2 包下创建个 User类
  }
    class Monster{ //

    }
  }

  package scala { //包 com.nuc.scala

    class Person { // 表示在 com.nuc.scala下创建类 Person
      val name = "Nick"

      def play(message: String): Unit = {
        println(this.name + " " + message)
      }
    }

    class User {

    }

    object Test100 { //表示在 com.nuc.scala 创建object Test
      def main(args: Array[String]): Unit = {
        println("ok")
        //我们可以直接使用父包的内容
        //1.如果有同名的类,则采用就近原则来使用内容(比如包)
        //2.如果就是要使用父包的类,则指定路径即可
        val user = new User
        println("user=" + user) //
        val user2 = new com.nuc.User()
        println("user2" + user2)

      }
    }
  }

}

④可以在同一个.scala文件中,声明多个并列的package(建议嵌套的pakage不要超过3层)

⑤包名可以相对也可以绝对,在一般情况下:我们使用相对路径来引入包,只有当包名冲突时,使用绝对路径来处理

package com.nuc.scala2

import scala.beans.BeanProperty

class Manager(var name: String) {
  //第一种形式 [使用相对路径引入包]
  @BeanProperty var age: Int = _
  //第二种形式, 和第一种一样,都是相对路径引入
  @scala.beans.BeanProperty var age2: Int = _
  //第三种形式, 是绝对路径引入,可以解决包名冲突
  @_root_.scala.beans.BeanProperty var age3: Int = _
}

object TestBean {
  def main(args: Array[String]): Unit = {
    val m = new Manager("jack")
    println("m=" + m)
  }
}

1.6、包对象

①基本介绍

​ 包可以包含类、对象和特质trait,但不能包含函数/方法或变量的定义。这是Java虚拟机的局限。为了弥补这一点不足,scala提供了包对象的概念来解决这个问题。

②示例
package com.nuc { //包 com.nuc

  //说明
  //1. 在包中直接写方法,或者定义变量,就错误==>使用包对象的技术来解决
  //2. package object scala 表示创建一个包对象 scala, 他是 com.nuc.scala这个包对应的包对象
  //3. 每一个包都可以有一个包对象
  //4. 包对象的名字需要和子包一样
  //5. 在包对象中可以定义变量,方法
  //6. 在包对象中定义的变量和方法,就可以在对应的包中使用
  //7. 在底层这个包对象会生成两个类 package.class  和 package$.class
  package object scala {
    var name = "king"

    def sayHiv(): Unit = {
      println("package object scala sayHI~")
    }
  }


  package scala { //包 com.nuc.scala

    class Person { // 表示在 com.nuc.scala下创建类 Person
      val name = "Nick"

      def play(message: String): Unit = {
        println(this.name + " " + message)
      }
    }

    class User {
      def testUser(): Unit = {
        println("name = " + name)
        sayHiv()
      }
    }

    object Test { //表示在 com.nuc.scala 创建object Test
      def main(args: Array[String]): Unit = {

        println("name=" + name)
        name = "yy"
        sayHiv()
      }
    }

  }

}
③注意事项
  1. 每个包都可以有一个包对象。你需要在父包中定义它
  2. 包对象名称需要和包名一致,一般用来对包的功能补充

1.7、包的可见性

①基本介绍

​ 在Java中,访问权限分为: public,private,protected和默认。在Scala中,你可以通过类似的修饰符达到同样的效果

②示例
object Testvisit {
  def main(args: Array[String]): Unit = {
    val  c = new Clerk()
    c.showInfo()
    Clerk.test(c)
  }}
class Clerk {
  var name : String = "jack"
  private var sal : Double = 9999.9
  def showInfo(): Unit = {
    println(" name " + name + " sal= " + sal)
  }}
object Clerk{
  def test(c : Clerk): Unit = {
    //这里体现出在伴生对象中,可以访问c.sal
    println("test() name=" + c.name + " sal= " + c.sal)
  }
 }

1.8、包的引入

① 基本介绍

​ Scala引入包也是使用import, 基本的原理和机制和Java一样,但是Scala中的import功能更加强大,也更灵活。

​ 因为Scala语言源自于Java,所以java.lang包中的类会自动引入到当前环境中,而Scala中的scala包和Predef包的类也会自动引入到当前环境中,即起其下面的类可以直接使用。

​ 如果想要把其他包中的类引入到当前环境中,需要使用import语言

② 注意事项

​ 1) 在Scala中,import语句可以出现在任何地方,并不仅限于文件顶部,import语句的作用一直延伸到包含该语句的块末尾。这种语法的好处是:在需要时在引入包,缩小import 包的作用范围,提高效率。

class User {
    import scala.beans.BeanProperty
    @BeanProperty var  name : String = ""
}
class Dog {
    @BeanProperty var  name : String = "" //可以吗?  no
}

​ 2) Java中如果想要导入包中所有的类,可以通过通配符*,Scala中采用下 _

​ 3) 如果不想要某个包中全部的类,而是其中的几个类,可以采用选取器(大括号)

def test(): Unit = {
    //可以使用选择器,选择引入包的内容,这里,我们只引入 HashMap, HashSet
    import scala.collection.mutable.{HashMap, HashSet}
    var map = new HashMap()
    var set = new HashSet()
  }

​ 4) 如果引入的多个包中含有相同的类,那么可以将不需要的类进行重命名进行区分,这个就是重命名

def test2(): Unit = {
    //下面的含义是 将 java.util.HashMap 重命名为 JavaHashMap
    import java.util.{ HashMap=>JavaHashMap, List}
    import scala.collection.mutable._
    var map = new HashMap() // 此时的HashMap指向的是scala中的HashMap
    var map1 = new JavaHashMap(); // 此时使用的java中hashMap的别名

  }

​ 5) 如果某个冲突的类根本就不会用到,那么这个类可以直接隐藏掉

import java.util.{ HashMap=>_, _} // 含义为 引入java.util包的所有类,但是忽略 HahsMap类.
var map = new HashMap() // 此时的HashMap指向的是scala中的HashMap, 而且idea工具,的提示也不会显示java.util的HashMaple 

2、访问修饰符

①基本介绍
  1. 当属性访问权限为默认时,从底层看属性是private的,但是因为提供了xxx_$eq()[类似setter]/xxx()[类似getter] 方法,因此从使用效果看是任何地方都可以访问)

  2. 当方法访问权限为默认时,默认为public访问权限

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

  4. protected为受保护权限,scala中受保护权限比Java中更严格,只能子类访问,同包无法访问

  5. 在scala中没有public关键字,即不能用public显式的修饰属性和方法。

  6. 包访问权限(表示属性有了限制。同时包也有了限制),这点和Java不一样,体现出Scala包使用的灵活性

object Demo3 {


  def main(args: Array[String]): Unit =
  {//增加包访问权限后,不仅同类可以使用,同时nuc包下的其他类也可以使用
    val d = new DD
    println(d.name)
  }

}
class DD{

  private[nuc] val name = "hello"

  //说明:private也可以变化,比如protected[nuc],非常灵活

}
②综合案例
package com.nuc.chapter07.visit

object Testvisit {
  def main(args: Array[String]): Unit = {
    val c = new Clerk()

    c.showInfo()
    Clerk.test(c)

    //创建一个Person对象
    val p1 = new Person
    println(p1.name)
  }
}

//类
class Clerk {
  var name: String = "jack" //
  private var sal: Double = 9999.9
  protected var age = 10
  var job : String = "大数据工程师"

  def showInfo(): Unit = {
    //在本类可以使用私有的
    println(" name " + name + " sal= " + sal)
  }
}

//当一个文件中出现了 class Clerk 和 object Clerk
//1. class Clerk 称为伴生类
//2. object Clerk 的伴生对象
//3. 因为scala设计者将static拿掉, 他就是设计了 伴生类和伴生对象的概念
//4. 伴生类 写非静态的内容 伴生对象 就是静态内容
object Clerk {
  def test(c: Clerk): Unit = {
    //这里体现出在伴生对象中,可以访问c.sal
    println("test() name=" + c.name + " sal= " + c.sal)
  }
}

class Person {
  //这里我们增加一个包访问权限
  //下面private[visit] : 1,仍然是private 2. 在visit包(包括子包)下也可以使用name ,相当于扩大访问范围

  protected[visit] val name = "jack"
}

3、scala之继承

① 基本介绍

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

② 示例

object Extends01 {
  def main(args: Array[String]): Unit = {
    //使用
    val student = new Student
    student.name = "jack" //调用了student.name() //调用到从Person继承的name()
    student.studying()
    student.showInfo()
  }
}

class Person { //Person类
  var name : String = _
  var age : Int = _
  def showInfo(): Unit = {
    println("学生信息如下:")
    println("名字:" + this.name)
  }
}

//Student类继承Person
class Student extends Person {
  def studying(): Unit = {
    //这里可以使用父类的属性
    println(this.name + "学习 scala中....")
  }
}

3.1、重写方法

① 基本介绍

说明: scala明确规定,重写一个非抽象方法需要用override修饰符,调用超类的方法使用super关键字

② 示例

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

    val emp = new Emp100
    emp.printName()
  }
}

//Person类
class Person100 {
  var name: String = "tom"

  def printName() { //输出名字
    println("Person printName() " + name)
  }

  def sayHi(): Unit = {
    println("sayHi...")
  }
}

//这里我们继承Person
class Emp100 extends Person100 {
  //这里需要显式的使用override
  override def printName() {
    println("Emp printName() " + name)
    //在子类中需要去调用父类的方法,使用super
    super.printName()
    sayHi()
  }
}

3.2、类型检查和转换

① 基本介绍

​ 要测试某个对象是否属于某个给定的类,可以用isInstanceOf方法。用asInstanceOf方法将引用转换为子类的引用。classOf获取对象的类名。

② 示例

classOf[String]就如同Java的 String.class
obj.isInstanceOf[T]就如同Java的obj instanceof T 判断obj是不是T类型。
obj.asInstanceOf[T]就如同Java的(T)obj 将obj强转成T类型。


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

    //ClassOf的使用,可以得到类名
    println(classOf[String]) // 输出
    val s = "king"
    println(s.getClass.getName) //使用反射机制

    //isInstanceOf asInstanceOf
    var p1 = new Person200
    var emp = new Emp200
    //将子类引用给父类(向上转型,自动)
    p1 = emp 
    //将父类的引用重新转成子类引用(多态),即向下转型
    var  emp2 = p1.asInstanceOf[Emp200]
    emp2.sayHello()


  }
}


//Person类
class Person200 {
  var name: String = "tom"

  def printName() { //输出名字
    println("Person printName() " + name)
  }

  def sayHi(): Unit = {
    println("sayHi...")
  }
}

//这里我们继承Person
class Emp200 extends Person200 {
  //这里需要显式的使用override
  override def printName() {
    println("Emp printName() " + name)
    //在子类中需要去调用父类的方法,使用super
    super.printName()
    sayHi()
  }

  def sayHello(): Unit = {

  }
}

3.3、scala中超类的构造

1)类有一个主构器和任意数量的辅助构造器,而每个辅助构造器都必须先调用主构造器(也可以是间接调用.)

2)只有主构造器可以调用父类的构造器。辅助构造器不能直接调用父类的构造器。在Scala的构造器中,你不能调用super(params)

[外链图片转存失败(img-5ke875tq-1566010671630)(D:/work/java/WorkSpace/MarkDown/scala/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/assets/1542887752448.png)]

object ScalaBaseConstrator {
  def main(args: Array[String]): Unit = {
    //分析一下他的执行流程
    //1.因为scala遵守先构建父类部分 extends Person700()
    //2.Person...

    //val emp = new Emp700()

    //分析一下他的执行流程
    //1.因为scala遵守先构建父类部分 extends Person700()
    //2.Person...
    //3.Emp .... (Emp700的主构造器)
    println("=====================")
    val emp2 = new Emp700("mary")


    println("**************************")
    //分析执行的顺序
    //1.Person...
    //2.默认的名字
    //3.Emp ....
    //4.Emp 辅助构造器~
    val emp3 = new Emp700("smith")

    //再测试一把
    //Person.. , name= "terry"
    //Emp ....
    val emp4 = new Emp700("terry", 10)
    emp4.showInfo() // 雇员的名字 terry

  }
}

//父类Person
class Person700(pName:String) {
  var name = pName
  println("Person...")
  def this() {
    this("默认的名字")
    println("默认的名字")

  }
}

//子类Emp继承Person
class Emp700(eName:String,eAge:Int) extends Person700(eName) {

  println("Emp ....")
  //辅助构造器
  def this(name: String) {

    this(name,100) // 必须调用主构造器
    this.name = name
    println("Emp 辅助构造器~")
  }
  
  def showInfo(): Unit = {
    println("雇员的名字 ", name)
  }
}

4、抽象类

① 基本介绍

​ 在Scala中,通过abstract关键字标记不能被实例化的类。方法不用标记abstract,只要省掉方法体即可。抽象类可以拥有抽象字段,抽象字段/属性就是没有初始值的字段

② 示例

object AbstractDemo01 {
  def main(args: Array[String]): Unit = {
    println("xxx")
  }
}

//抽象类
abstract class Animal{
  var name : String //抽象的字段
  var age : Int // 抽象的字段
  var color : String = "black" //普通属性
  def cry() //抽象方法,不需要标记 abstract
}

③ 抽象类的注意细节

//默认情况下,一个抽象类是不能实例化的,但是你实例化时,动态的实现了抽象类的所有
    //抽象方法,也可以先,如下
    val animal = new Animal03 {
      override def sayHello(): Unit = {
        println("say hello~~~~")
      }
    }
    animal.sayHello()

2) 抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法
abstract class Animal02 {
  //在抽象类中可以有实现的方法
  def sayHi (): Unit = {
    println("xxx")
  }
}

3) 一旦类包含了抽象方法或者抽象属性,则这个类必须声明为abstract
4) 抽象方法不能有主体,不允许使用abstract修饰
5) 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法和抽象属性,除非它自己也声明为abstract类
abstract class Animal03 {
  def sayHello() 

  var food: String
}


class Dog extends Animal03 {
  override def sayHello(): Unit = {
    println("小狗汪汪叫!")
  }

  override var food: String = _
}

6) 抽象方法和抽象属性不能使用private、final 来修饰,因为这些关键字都是和重写/实现相违背的
7) 抽象类中可以有实现的方法.
8) 子类重写抽象方法不需要override,写上也不会错.

5、继承层级

[外链图片转存失败(img-yGlelz9B-1566010671632)(D:/work/java/WorkSpace/MarkDown/scala/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/assets/1542888313642.png)]

  1.  在scala中,所有其他类都是`AnyRef`的子类,类似Java的Object。
    
  2.  `AnyVal和AnyRef都扩展自Any类`。Any类是根节点
    
  3.  Any中定义了isInstanceOf、asInstanceOf方法,以及哈希方法等。
    
  4.  Null类型的唯一实例就是null对象。可以将null赋值给任何引用,但不能赋值给值类型的变量
    
  5.  Nothing类型没有实例。它对于泛型结构是有用处的,举例:空列表Nil的类型是List[Nothing],它是List[T]的子类型,T可以是任何类。
    
发布了32 篇原创文章 · 获赞 39 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/yang735136055/article/details/99690319