Scala核心编程_第07章 面向对象编程(中级部分)

scala包

回顾-Java包的三大作用

  1. 区分相同名字的类
  2. 当类很多时,可以管理类
  3. 控制访问范围

回顾-Java打包与导入包

打包基本语法

package com.公司名.项目名;

打包的本质分析

实际上就是创建不同的文件夹来保存类文件

语法: import 包;

import java.awt.*;
import java.util.Scanner;

引入一个包的主要目的是要使用该包下的类,或者通配符表示所有类。

Scala包的特点概述

基本语法 package 包名

Scala包的三大作用(和Java一样)

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

Scala中包名和源码所在的系统文件目录结构要可以不一致,但是编译后的字节码文件路径和包名会保持一致(这个工作由编译器完成)。

Scala包的命名

命名规则:

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

package com.xgo.class. //错误 , 因为class是关键字
package com.xgo.12a // 错误,因为不能以数字开头

命名规范:

一般是小写字母+小圆点一般是
com.公司名.项目名.业务模块名
比如:

com.xgo.oa.model com.xgo.oa.controller
com.sina.edu.user
com.sohu.bank.order

Scala会自动引入的常用包

java.lang.*

scala包(Predef在)

Scala包注意事项和使用细节

1.scala进行package 打包时,可以有如下形式,三种方式等同。

代码说明 传统的方式

package com.xgo.scala
class Person{
  val name = "wqbin"
  def play(message: String): Unit ={println(this.name + " " + message)
  }
}

代码说明 :和第一种方式完全等价

package com.xgo
package scala
class Person{
  val name = “wqbin”
  def play(message: String): Unit ={println(this.name + " " + message)
  }
}

代码说明 :和第一种方式完全等价

package com.xgo{
  package scala{
    class Person{
      val name = “wqbin"
      def play(message: String): Unit ={println(this.name + " " + message)
      }
    }
  }
} 

2.包可以嵌套使用。

    可以在同一个文件中,将不同的类(class / object)、trait 创建在不同的包中

package com.xgo{
    trait Person1{
      val name = “wqbin"
      def play(message: String): Unit ={println(this.name + " " + message)
      }
  package scala{
    class Person2{
      val name = “wqbin"
      def play(message: String): Unit ={println(this.name + " " + message)
      }
    }
  }
} 

3.作用域原则:可以直接向上访问。

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

package com.xgo{
  //这个类就是在com.xgo
  class User{
  }
  //这个类对象就是在Monster$ , 也在com.xgo
  object Monster {
  }
  class Dog {
  }
  package testpack {
    //这个类就是在com.xgo.scala包下
    class User{
    }
    //这个Test 类对象
    object Test {
      def main(args: Array[String]): Unit = {
        //子类可以直接访问父类的内容
        var dog = new Dog()
        println("dog=" + dog)
        //在子包和父包 类重名时,默认采用就近原则.
        var u = new User()
        println("u=" + u)
        //在子包和父包 类重名时,如果希望指定使用某个类,则带上包路径
        var u2 = new com.xgo.User()
        println("u2=" + u2)
      }
    }
  }
}

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

package com.xgo{
  //如果要在父包使用到子包的类,需要import
  //引入在com.xgo 包中希望使用到子包的类Tiger,因此需要引入.
  import com.xgo.xgoDemo.Tiger
  //这个类就是在com.xgo
  class User{
  }
  package xgoDemo {
    //Tiger 在 com.xgo.scala 包中
    class Tiger {}}
  object Test2 {
    def main(args: Array[String]): Unit = {

      val tiger = new Tiger()
      println("tiger=" + tiger)
    }}}

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

6.包名可以相对引入也可以绝对引入

比如,访问BeanProperty的绝对路径是:

_root_. scala.beans.BeanProperty ,在一般情况下:我们使用相对路径来引入包,只有当包名冲突时,使用绝对路径来处理

package com.xgo
class Manager( var name : String ) {
  //第一种形式
  //@BeanProperty var age: Int = _
  //第二种形式, 和第一种一样,都是相对路径引入
  //@scala.beans.BeanProperty var age: Int = _
  //第三种形式, 是绝对路径引入,可以解决包名冲突
  @_root_. scala.beans.BeanProperty var age: Int = _
}
object TestBean {
  def main(args: Array[String]): Unit = {
    val pm = new Manager("wqbin")
    println("pm=" + pm)
  }}

包对象

包对象的基本介绍

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

只要对被修饰的包,同包级别增加一个同名package object包对象就OK,在其中添加 函数/方法或变量的定义。

  package object xxx{
    方法...变量
}
  package xxx{

}

package com.xgo {
  //每个包都可以有一个包对象。你需要在父包(com.xgo)中定义它,与被修饰的包同名。
  package object wqbin {
    var name = "wqbin"

    def sayOk(): Unit = {
      println("package object sayOk!")
    }
  }
  package wqbin {
    class Test {
      def test(): Unit = {
        //这里的name就是包对象wqbin中声明的name
        println(name)
        sayOk() //这个sayOk 就是包对象wqbin中声明的sayOk
      }
    }
    object TestObj {
      def main(args: Array[String]): Unit = {
        val t = new Test()
        t.test()
        //因为都在包wqbin下,因此也可以使用
        println("name=" + name)
      }
    }
  }
}

包对象的底层实现机制分析(重点)

说明:看反编译代码+分析图

 包对象的本质是在这个包下生成了两个类:

  • public final class package
  • public final class package$

其中这个public final class package$类含有这个单独维护着这个包的函数/方法或变量的定义。

scala包的可见性

回顾-Java访问修饰符基本介绍

java提供四种访问控制修饰符号控制方法和变量的访问权限(范围):

  • 公开级别:用public 修饰,对外公开
  • 受保护级别:用protected修饰,对子类和同一个包中的类公开
  • 默认级别:没有修饰符号,向同一个包的类公开.
  • 私有级别:用private修饰,只有类本身可以访问,不对外公开.

回顾-Java中4种访问修饰符的访问范围

 

Scala中包的可见性介绍:

在Java中,访问权限分为: public,private,protected和默认。在Scala中,可以通过类似的修饰符达到同样的效果。但是使用上有区别。

Scala中包的可见性和访问修饰符的使用

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

class Dog{
  val gender="female"
  var age=5
}

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

class Dog{
  private val gender="female"
  private var age=5
}

3.protected为受保护权限,scala中受保护权限比Java中更严格,只能子类访问,同包无法访问 (编译器)

class Dog{
  var gender="female"
  protected var age=5
}
class Ted extends Dog{
  this.age=10 //子类可以访问父类
  this.gender="male"
}

object TestMain{

  def main(args: Array[String]): Unit = {
    var dog=new Dog()
    dog.age//报错==>同包无法访问
    dog.gender="trans"
  }
} 

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

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

package com.wqbin.scala
class Person {
  private[scala] val pname="hello" // 增加包访问权限后,1.private同时起作用。不仅同类可以使用 2. 同时com.wqbin.scala中包下其他类也可以使用
}
当然,也可以将可见度延展到上层包
private[wqbin] val description="wang"
说明:private也可以变化,比如protected[wqbin], 非常的灵活。

scala包的引入

Scala引入包基本介绍

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

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

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

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

class User {
    import scala.beans.BeanProperty
    @BeanProperty var  name : String = ""
}

2.导入包中所有的类,Scala中采用通配符 _ ,而Java通过通配符*

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

def test(): Unit = {
  import scala.collection._
  import scala.collection.mutable.{HashMap, HashSet}
  var map = new HashMap()
  var set = new HashSet()
}

4.如果引入的多个包中含有相同的类,将冲突类进行重命名以区分。=>

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 

完结!!

原文地址:https://www.cnblogs.com/wqbin/p/12934663.html