scala语法(三)(有java基础速学)

面向对象编程(中)


scala的包

Scala中包名和源码所在的系统文件目录结构要可以不一致,但是编译后的字节码文件路径和包名会保持一致
在这里插入图片描述


scala 自动引入的包

Scala中,以下三个包的内容会隐式引用到每个程序上。

import java.lang._ // in JVM projects, or system namespace in .NET
import scala._     // everything in the scala package
import Predef._    // everything in the Predef object

scala 包使用注意事项

  1. 在scala中一个文件可以同时创建多个包
  2. 在scala中一个文件可以在不同的包下,创建多个class,object,trait
  3. 包也可以像嵌套类那样嵌套使用(包中有包)
  4. 父包要访问子包的内容时,需要import对应的类等
  5. 可以在同一个.scala文件中,声明多个并列的package(建议嵌套的pakage不要超过3层)
  6. 包名可以相对路径也可以绝对路径
package p1 {
//表示在xxx.p1包下创建了Car的class
  class Car
  
  package p2 {
  	// 父包要访问子包的内容时,需要import对应的类等
    import Test.name
	//表示在xxx.p1.p2包下创建了class Test的伴生类和class Test$的伴生对象 
    object Test {
      // BeanProperty 所在包绝对路径
   	  @_root_.scala.beans.BeanProperty 
      var name: String = _
      def main(args: Array[String]): Unit = {
        print("路径xxx/p1/p2/下")
      }
    }
	//表示在xxx.p1.p2包下创建了Test2的class 
    class Test2
	//表示在xxx.p1.p2包下创建了Test4的特质
    trait Test3

  }

}

包对象

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

  1. 每个包都可以有一个包对象。你需要在父包中定义它
  2. 包对象名称需要和包名一致,一般用来对包的功能补充
package object p1 {
  var name = "jack" //变量
  def sayHi(): Unit = { //方法
    println("package object p1()")
  }
}
package p2 {

  package p3 {

    //这个包下创建了 class Test[伴生类] 和 class Test  [伴生对象]
    object Test {
      def main(args: Array[String]): Unit = {
        //使用对应的包对象的内容
        println("name=" + p1.name)
        p1.sayHi()
        println(p2.p2_name)
      }
    }
  }
}
//p2包功能补充
package object p2{
  var p2_name = "nico" //变量
}
name=jack
package object p1()
nico

scala可见性与修饰符

与java类似

  1. 当属性访问权限为默认时,从底层看属性是private的,但是因为提供了xxx_$eq()[类似setter]/xxx()[类似getter] 方法,因此从使用效果看是任何地方都可以访问)
  2. 当方法访问权限为默认时,默认为public访问权限
  3. private为私有权限,只在类的内部和伴生对象中可用
  4. protected为受保护权限,scala中受保护权限比Java中更严格,只能子类访问,同包无法访问 (编译器从语法层面控制)
  5. 在scala中没有public关键字,即不能用public显式的修饰属性和方法

object Test {
  def main(args: Array[String]): Unit = {
    val clerk = new Clerk
    clerk.showInfo()
    test(clerk)
    //    clerk.name = "zs" //默认修饰符 但提供了Publicd的方法
    //    clerk.age = 10 //访问不到
    //    clerk.job = "hhh" //访问不到
  }
}
//1. 如果我们在同一个文件中,写了 class Clerk 和  object Clerk
//   就把 class Clerk 称为 伴生类, object Clerk 称为伴生对象
//2. 如果我们在同一个文件中,只写了 class Clerk ,那么Clerk就是一个普通的类
//3. 如果我们在同一个文件中,只写了 object Clerk, 那么在底层就会自动生成对应的伴生类 class Clerk, 只是这个伴生类是空..
//4. 伴生对象,可以访问到伴生类的任何方法和属性

class Clerk {
  //var name , 底层 name是private ,但是会提供两个public方法 name name_$eq
  var name: String = "zs"
  //protected var age ,底层 age 是private , 会提供两个pulbic方法 age 和 age_$eq
  protected var age: Int = 10

  private var color: String = "white"

  def showInfo(): Unit = {
    println("showInfo() name=" + name + " age= " + age + " color= " + color) //c.color()
  }

}

object Clerk {
  def test(c: Clerk): Unit = {
    c.name = "ls"
    c.age = 20
    c.color = "red"
    //这里体现出在伴生对象中,可以访问c.sal[sal是私有]
    println("test() name=" + c.name + " age= " + c.age + " color= " + c.color) //c.color()

  }
}
showInfo() name=zs age= 10 color= white
test() name=ls age= 20 color= red

面向对象编程方法——抽象

与java类似,实际上就是把一类事物的共有的属性和行为提取出来,形成一个物理模型(模板)。这种研究问题的方法称为抽象。
如 猫 狗 大象 ==》抽象成动物, 提取属性颜色、年龄 ,提取行为 吃饭、睡觉

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

object Test{
  def main(args: Array[String]): Unit = {
    val mouse: Mouse = new Mouse
    mouse.sayOk()
    mouse.cry()
    println("ok~~")
  }
}

//抽象类
abstract class Animal {
  var name: String //抽象的字段
  var age: Int // 抽象的字段
  var color: String = "black" //普通字段

  def cry() //抽象方法

  def sayOk(): Unit = {
    println("ok")
  }
}

//快捷键 alt+enter
class Mouse extends Animal {

  override var name: String = "Mouse"
  override var age: Int = 10

  //以后再scala中,override 有两层含义 1. 重写(override 必须保留)继承普通类 2. 实现 (可以省略) 继承抽象类
  //  override def cry(): Unit = {
  //
  //  }
  def cry(): Unit = {
    println(name + " " + age)
  }
}

ok
Mouse 10
ok~~

面向对象的三大特征——封装

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

object Test {
  def main(args: Array[String]): Unit = {
    val p = new Person
    p.getInfo()
    
  }
}
class Person{
  private var name: String = _
  private var age: Int = _
  private var salary: Double = _

  def getInfo(): Unit = {
    println(name + " " + age + " " + salary)
  }
}

面向对象的三大特征——继承

写一个非抽象方法需要用override修饰符,调用超类的方法使用super关键字

object Test{
  def main(args: Array[String]): Unit = {
    val t = new Teacher
    t.age = 10
    t.name = "zs"
    t.salary = 10.55
    t.teach
    t.getInfo
  }
}
class Person1 {
  var name: String = _  //name 属性private 底层调用set方法public
  var age: Int = _
  var salary: Double = _

  def getInfo(): Unit = {
    println(name + " " + age + " " + salary)
  }
}
//继承
class Teacher extends Person1 {
  def teach(): Unit = {
  	//调用父类方法
  	super.getInfo()
    println("teach english")
  }
//重写方法
  override def getInfo(): Unit = {
    println(name + "___" + age + "___" + salary)
  }
}
zs
teach english
zs___10___10.55

面向对象的三大特征——多态及类型检查和转换

  1. isInstanceOf,测试某个对象是否属于某个给定的类。
  2. asInstanceOf,将引用转换为子类的引用。
  3. classOf,获取对象的类名。
object TypeConvert {
  def main(args: Array[String]): Unit = {
    // 获取对象类型
    println(classOf[String])
    val s = "zhangsan"
    println(s.getClass.getName) //这种是Java中反射方式得到类型
    println(s.isInstanceOf[String]) //判断类型 true
    println(s.asInstanceOf[String]) //将s 显示转换成String

    val p1: Father = new Son1 //子类对象给了一个父类的引用
    p1.printName()
    p1.asInstanceOf[Son1].say()
    p1.asInstanceOf[Son1].printName1()

    val p2: Father = new Son2 //子类对象给了一个父类的引用
    p2.printName()
    //如果希望使用的子类的方法say
    p2.asInstanceOf[Son2].say()
    p2.asInstanceOf[Son2].printName2()
  }
}

class Father {
  var name = "king"

  def printName(): Unit = {
    println("FatherName=" + name)
  }
}

class Son1 extends Father {
  def say(): Unit = {
    println("Son1=" + name)
  }
  //继承父类 同名方法就得重写
  override def printName(): Unit = {
    println("Son1Name=" + name)
  }
  def printName1(): Unit = {
    println("Son1Name=")
  }
}


class Son2 extends Father {
  def say(): Unit = {
    println("Son2=" + name)
  }
  //继承父类 同名方法就得重写
  override def printName(): Unit = {
    println("Son2Name=" + name)
  }

  def printName2(): Unit = {
    println("Son2Name")
  }
}

class java.lang.String
java.lang.String
true
zhangsan
Son1Name=king
Son1=king
Son1Name=
Son2Name=king
Son2=king
Son2Name

Scala中超类的构造

  1. 类有一个主构器和任意数量的辅助构造器,而每个辅助构造器都必须先调用主构造器
  2. 只有主构造器可以调用父类的构造器。辅助构造器不能直接调用父类的构造器。在Scala的构造器中,你不能调用super(params)
object SuperDemo {
  def main(args: Array[String]): Unit = {
    new Emp5()
  }
}

class Person5(name: String) { //父类的构造器
  println("Person5 主构造器" + name)
}

class Emp5(name: String) extends Person5(name) { // 将子类参数传递给父类构造器,这种写法√
  println("子类的主构造器=" + name)
  //super(name), 错误不能在主构造器中显式的调用super

  def this() {
    this("xxx")
    //super("abc") // (×)不能在辅助构造器中调用显式父类的构造器
  }
}
Person5 主构造器xxx
子类的主构造器=xxx

匿名类

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

//抽象类,他不能实例化,我们可以通过匿名子类的方式创建一个实例
abstract class Monster {
  var name: String

  def cry()
}

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

    //匿名子类创建对象实例比较灵活.
    val monster = new Monster {
      override def cry(): Unit = {
        println("啊啊啊啊啊")
      }

      override var name: String = _
    }
    monster.cry()

    val monster1 = new Monster {
      override def cry(): Unit = {
        println("aaaaaaa")
      }

      override var name: String = _
    }
    monster1.cry()
  }
}



啊啊啊啊啊
aaaaaaa
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值