类成员访问修饰符
Modifier | Class | Package | Subclass | World |
---|---|---|---|---|
public | Y | Y | Y | Y |
protected | Y | Y | Y | N |
default | Y | Y | N | N |
private | Y | N | N | N |
Modifier | Class | Companion | Subclass | Package | World |
---|---|---|---|---|---|
default(public) | Y | Y | Y | Y | Y |
protected | Y | Y | Y | N |
N |
private | Y | Y |
N | N | N |
类的定义
//主构造器的参数列表直接定义在类名后面
class Point(xc: Int, yc: Int) {
var x: Int = xc //成员变量
var y: Int = yc
//辅助构造器
def this() ={
this(0, 0) //第一句必须调用其他构造器
}
//成员方法
def move(dx: Int, dy: Int) ={
x = x + dx
y = y + dy
}
}
var p=new Point()
p.x
p.y
p=new Point(12,11)
p.x
p.y
p.move(1,2)
类的继承
extends
关键字实现继承override
关键字class BlackPoint() extends Point {
private var color="black"
override def move(dx: Int, dy: Int) ={
x = x + dx
y = y + dy
println("moved to x:"+x+" y:"+y)
}
}
var bp=new BlackPoint()
bp.x
bp.y
bp.move(1,2)
抽象类
override
关键字可选override
关键字必写abstract class Shape{
def draw():Unit
}
class Square extends Shape{
override def draw():Unit={
println("draw a square")
}
}
var shape=new Square
shape.draw
object
关键字声明,可包含变量、方法与代码定义定义单例对象
//Blah.scala
package test //定义包名
//定义单例对象
object Blah {
println("Blah initializing...")
def sum(l: List[Int]): Int = l.sum
}
test.Blah.sum(List[Int](1, 2, 3, 4, 5))
伴生(Companion)
伴生类与伴生对象
//Student.scala
//伴生类
class Student(n: String, a: Int) {
private var name = n //私有变量,伴生对象可以访问
private var age = a
}
//伴生对象
object Student {
//伴生对象的apply方法可以使得不用new对象
def apply(n: String, a: Int): Student = new Student(n, a)
def main(args: Array[String]): Unit = {
val stu=Student("Jason",9) //通过伴生对象的apply()方法创建实例
println(stu.name)
}
}
interface
的概念extends
trait
关键字定义override
使用特质
import scala.collection.mutable.ArrayBuffer
trait Pet {
val name: String
def cry():Unit
}
class Dog(val name: String) extends Pet{
override def cry()=println("wow ...")
}
val dog = new Dog("Harry")
val animals = ArrayBuffer.empty[Pet]
animals.append(dog)
animals.foreach(pet => {println(pet.name);pet.cry()}) // Prints Harry wow ...
混入特质(mixin)
abstract class A {
val message: String
}
class B extends A {
val message = "I'm an instance of class B"
}
trait C extends A {
def loudMessage = message.toUpperCase()
}
//构造顺序由左往右,如果前面已经构造了某个父类,后面子类的该父类不会重复构造
class D extends B with C
val d = new D
println(d.message) // I'm an instance of class B
println(d.loudMessage) // I'M AN INSTANCE OF CLASS B
动态混入特质
class Drawing {
//this:Type=> 自身类型,表示该类实例化时必须混入相应特质或子特质,self是this的别名。
self: Shape =>
def start(): Unit = draw()
}
trait Shape {
def draw(): Unit
}
trait Square extends Shape {
def draw(): Unit = println("draw a square")
}
trait Triangle extends Shape {
def draw(): Unit = println("draw a triangle")
}
//动态混入
(new Drawing() with Square).start()
(new Drawing() with Triangle).start()
特质与抽象类的选择
1.优先使用特质
2.需要使用带参构造方法时,使用抽象类
3.与Java互操作性
一个类可以作为另一个类的成员,称为内部类
class Graph {
class Node {
var connectedNodes: List[Node] = Nil
def connectTo(node: Node) {
if (connectedNodes.find(node.equals).isEmpty) {
connectedNodes = node :: connectedNodes
}
}
}
var nodes: List[Node] = Nil
def newNode: Node = {
val res = new Node
nodes = res :: nodes
res
}
}
val g: Graph = new Graph
val n1: g.Node = g.newNode
val n2: g.Node = g.newNode
n1.connectTo(n2) // legal
val h: Graph = new Graph
val n3: h.Node = h.newNode
n1.connectTo(n3) // illegal!
//n1与n3被认为是不同的类型
class Graph {
class Node {
var connectedNodes: List[Graph#Node] = Nil
def connectTo(node: Graph#Node) {//可以接受任意外部类对象实例中的内部类
if (connectedNodes.find(node.equals).isEmpty) {
connectedNodes = node :: connectedNodes
}
}
}
var nodes: List[Node] = Nil
def newNode: Node = {
val res = new Node
nodes = res :: nodes
res
}
}
case class Student(name:String,age:Int) //定义样例类
val stu=Student("Jason",19) //创建样例类的实例,无需new关键字
println(stu.name) //访问对象属性
注意: unapply()接受一个对象,从对象中提取出相应的值,主要用于模式匹配中
样例类与枚举(Enumeration)
object Weekday extends Enumeration {
//枚举值从0开始计数
val Mon,Tue,Wed,Thu,Fri,Sat,Sun=Value
}
//枚举的使用
Weekday.Sun
Weekday.Sun.id //获取枚举值的计数值
Weekday.values.foreach(println)
abstract class Term(code: String)
case class Var(name: String) extends Term(name)
case class Fun(arg: String, body: Term) extends Term(arg)
case class App(f: Term, v: Term) extends Term("App")
样例类与普通类
[]
class Stack[T] {
var elements: List[T] = Nil
def push(x: T) { elements = x :: elements }
def top: T = elements.head
def pop() {
var t = elements.head
elements = elements.tail
t
}
def showElements(){
elements.foreach(x=>print(s"$x "));println()}
}
val ms = new Stack[Int]()
ms.push(10)
ms.showElements()
ms.push(20)
ms.showElements()
val t = ms.pop()
ms.showElements()
协变
class Foo[+T] // 协变类
逆变
class Bar[-T] // 逆变类
不变
class Baz[T] // 不变类
Scala包:package 包名
package com.kgc{
package scala1 {... }
package scala2 {... }
}
package scala3 {... }
Scala包对象
包对象
解决这个问题package com.kgc{
package object scala { //对应包com.kgc.scala,每个包都可以有一个包对象
val name="Wow"
}...
package scala{...}//与包对象同名的包可直接使用包对象中定义的变量和方法
}
包引用
//易于访问Fruit
import cn.kgc.Fruit
//易于访问cn.kgc的所有成员
import cn.kgc._
//易于访问cn.kgc.Fruits的所有成员
import cn.kgc.Fruits._
//只引用Apple与Orange,并且Apple重命名为McIntosh
import cn.kgc.Fruits.{Apple=>McIntosh,Orange}
def showFruit(fruit:Fruit){
import fruit._
println(name+color)
}
package oop
/* 练习一
假设类Book有属性title和author(多个),books是Book的列表
实现Book类,同时使用主构造器与辅助构造器
实现Book的伴生对象,使用伴生对象创建Book实例
创建books,使用List[Book]初始化5个以上Book实例
找出books中书名包含“xxx”的书,并打印书名
找出books中作者名以“xxx”打头的书,并打印书名
*/
/* 练习二
现在Book拥有电子版本,可以在多终端上播放
定义Ebook特质,包含play()方法
使Book混入Ebook特质,实现play()方法
*/
class Book(var title:String= "",var authors:String= "")
object Book{
def apply(title:String,authors:String*): Book = new Book(title,authors.mkString(" "))
}
trait Ebook{
def play(book: Book)=println(book.title+"正在播放")
}
object Practice extends App {
//创建books
private val books = List[Book](Book("西游记","张三","李四"),
Book("二本书","王五","赵六"),
Book("红楼梦","王五","申九"),
Book("四本书","赵六","李四"),
Book("五本书","宫八","李四"),
Book("水浒传","申九","李四"))
//找出books中书名包含“xxx”的书,并打印书名
books.filter(_.title.contains("西游")).foreach(x=>println("书名:"+x.title))
//找出books中作者名以“xxx”打头的书,并打印书名
books.filter(x=>{x.authors.split("\\s+").
exists(x=>x.startsWith("申"))}).
foreach(x=>println("书名:"+x.title+" 作者:"+x.authors))
//特质
val book = new Book("西游记") with Ebook
//执行特质方法
book.play(book)
}