Scala包
- 一个源文件中可以有多个packge
- 子包中的类可以直接访问父包中的内容,无需导包
实例:
package com{
// 在外层包中定义单例对象
object Outer{
var out: String = "out"
def main(args: Array[String]): Unit = {
Inner // 不能在外层调用内层对象
//通过导入包可以访问
import com.atguigu.scala.Inner
println(Inner.in)
}
}
package atguigu{
package scala{
// 内层包中定义单例对象
Object Inner{
val in: String = "in"
def main(args: Array[String]): Unit = {
println(Outer.out) // 访问
Outer.out = "outer" // 更改
}
}
}
}
}
// 在同一文件中定义多个包
package aaa{
package bbb{
import com.atguigu.scala.Inner
object Test{
def main(args: Array[String]): Unit = {
println(Inner.in)
}
}
}
}
包对象
- 与包同名的对象,定义在包对象中的成员,作为其对应包下所有class和object的共享变量,可以直接访问 ```scala package object chapter{ // 定义当前包共享的属性和方法 val commonValue = “NJU” def commonMethod() = { println(s”我们在${commonValue}学习”) } }
// 在同一个包下可以调用
- 必须在同一层级下调用
<a name="nsa2J"></a>
### 导包
1. import可以在顶部使用
1. 局部导入。作用范围内可以使用
1. 通配符导入: import java.util._
1. 给类起名:import java.util.{ArrayList => JL} // 将ArrayList类起别名为JL
1. 导入相同包的多个类:import java.util.{HashSet, ArrayList}
1. 屏蔽类:import java.util.{ArrayList => _,_} //导入util下的所有包,不导入ArrayList
Scala中三个默认导入:
1. import java.lang._
1. import scala._
1. import scala.Predef._
<a name="APRqc"></a>
## 类和对象
<a name="IBmEH"></a>
### 定义类
**Java中**<br />如果是public的,则必须和文件名一致<br />一般,一个.java有一个public类<br />**Scala**<br />Scala中没有public(默认就是public)<br />一个.scala中可以写多个类<br />**Class没有实现可以不写大括号**<br />**创建对象时如果构造器为空,创建对象时可以不写小括号**<br />val类型必须手动初始化,var类型可以使用_ 指定默认值
```scala
class Student{
// 定义属性
private var name: String = "alice"
@BeanProperty // 自动创建getter setter...
var age: Int = 18
var sex: String = _ // 默认初始值
}
object Test {
def main(args: Array[String]): Unit = {
// 创建对象
val student = new Student()
// 不能 student.name
println(student.age)
student.sex = "female"
}
}
封装
Scala中的public属性,底层实际为private,并通过get方法和set方法对其进行操作。所以Scala并不推荐将属性设置为private,但由于Java框架都利用反射调用getXXX/setXXX方法,有时候为了兼容,为Scala属性设置getset方法(通过@BeanProperty注解实现)
访问权限
- Scala中属性默认访问权限public,但无该关键字
- private为私有权限,只在类的内部和伴生对象中可用
- protected为受保护权限,Scala中同类子类可以使用,同包无法使用
- private[包名] 增加包访问权限,包名下其它类可以使用
- private可以在伴生类伴生对象中互相访问,private[this] 伴生类都不能访问 ```scala package chapter
// 定义一个父类 class Person { private var idCard: String = “3322” protected var name: String = “alice” var sex String = “female” private[chapter] var age: Int = 18
def printInfo(): Unit = { println(s”Person: $idCard $name $sex $age”) } }
// 定义一个子类 class Worker extends Person { override def printlnInfo(): Unit = { // println(idCard) 不能访问 name = “bob” age = 25 sex = “male” println(s”Worker: $name $sex $age”) } }
object Test { def main(args: Array[String]): Unit = { val person: Person = new Person() // person.idCard //error // person.name // error println(person.age) println(person.sex) person.printInfo()
val worker: Worker = new Worker()
worker.printInfo()
} }
<a name="dJlFT"></a>
### 构造器
Scala类构造器包括主构造器和辅助构造器<br />**主构造器**
- 主构造器参数列表直接定义在类名后面,添加了val/var表示直接通过主构造器定义成员变量
- 构造器参数列表可以有默认值
- 创建实例,调用构造器可以指定字段进行初始化
- 整个class中除了字段定义和方法定义的代码都是构造代码
```scala
class 类名(形参列表) { // 主构造器
// 类体
def this(形参列表) { // 辅助构造器
}
def this(形参列表) { // 辅助构造器可以有多个
}
}
object Test {
Class Person(val name: String = "张三", val age: Int = 23) {
println("调用主构造器")
}
def main(args: Array[String]): Unit = {
val person1 = new Person
val person2 = new Person("李四", 24)
val person3 = new Person(age =30)
说明:
- 辅助构造器,函数名称this,可以有多个,编译器通过参数个数及类型区分
- 辅助构造方法不能直接创建对象,第一行代码必须直接或间接调用主构造方法
构造器调用其它另外的构造器,要求被调用的必须提前声明 ```scala object Test { def main(args: Array[String]): Unit = { val student1 = new Student //可以省略括号 输出:1. 主构造方法调用 student1.Student() // 输出:一般方法被调用
val student2 = new Student1(“alice”) // 1. 2. 被调用 val student3 = new Student1(“Bob”, 18) // 1.2.3.都被调用 } }
class Student1() { // 括号一般省略 var name: String = //默认null var age: Int = // 默认0
println(“1. 主构造方法调用”)
//辅助构造器 def this(name:String) { this() // 直接调用主构造方法 println(“2. 辅助构造方法”) this.name = name println(s”name: $name age: $age”) }
def this(nameL String, age: Int) { this(name) // 间接调用主构造器 println(“3. 辅助构造方法二被调用”) this.age = age println(s”name: $name age: $age”) }
def Student(): Unit = { println(“一般方法被调用”) } }
<a name="MzXDj"></a>
#### 构造器参数
- Scala类的主构造器形参包括三种类型:未用任何修饰、var修饰、val修饰
1. 未用任何修饰符,这个参数为局部变量
1. var,作为类的成员属性使用,可以修改
1. val,作为类只读属性使用,不能更改
```scala
class Student1 {
var name: String = _ //这里必须是var
var age: Int = _
}
class Student2(var name: String, var age: Int)
// 主构造器参数无修饰符
class Student3(name: String, age: Int)
object Test {
def main(args: Array[String]): Unit = {
// 方式一
val student1 = new Student1
student1.name = "alice"
student1.age = 21
//如果不想这样设置参数,想像下面一样,就得在类中增加辅助构造器
println(s"student1: name = ${student1.name}, age = ${student1.age}")
//方式二
val student2 = new Student2("Bob", 12)
println(s"student2: name = ${student2.name}, age = ${student2.age}")
val student3 = new Student3("xxx",111)
println(s"student3: name = ${student3.name}, age = ${student3.age}")// 这样就不行,name和age不是student3的属性
}
}
主构造器+辅助构造器
class Student4(var name: String, var age: Int) {
var school: String = _
def this(name: String, age: Int, school: String) {
this(name,age)
this.school = school
}
def this(arys: Array[String]) {
this(arys(0), arys(1))
}
apply方法
在Scala中,支持创建对象不写new关键字,对此就要通过伴生对象的apply()方法实现
apply必须在object里
object Test {
// 定义Person类
class Person(var name: String = "", var age: Int = 0) {}
// 定义Person伴生对象
object person {
// 定义apply方法
def apply(name: String, age: Int) = new Person(name,age)
}
def main(args: Array[String]): Unti = {
val p = Person("张三", 23) // 调用apply方法
println(p.name, p.age)
}
定义时间工具类
object ClassDemo {
// 定义工具类
object DateUtils {
// 定义SimpleDateFormat类型对象
var sdf: SimpleDateFormat = null
// 定义date2String方法,用来将日期转化成对应字符串
def date2String(date: Date, template: String) = {
sdf = new SimpleDateFormat(template)
sdf.format(date)
}
// 定义string2Date方法
def string2Date(dataString: String, template: String) = {
sdf = new SimpleDateFormat(template)
sdf.parse(dataString)
}
}
def main(args: Array[String]): Unti = {
println(DateUtils.date2String(new Date(), "HH:mm:ss"))
println(DateUtils.string2Date("1314年5月22日","yyyy年MM月dd日"))
}
}
继承和多态
class/object A类 extends B类 {}
- 类和单例对象都可以有父类 ```scala class Person { var name = “” def sayHello() = println(“Hello, Scala..”) }
object Student extends Person
def main(args: Array[String]): Unit = { Student.name = “张三” println(Student.name) Student.sayHello() }
- 继承的调用顺序:父类构造器->子类构造器
```scala
object Test {
def main(args: Array[String]): Unit = {
val student1 = new Student
}
}
class Person {
var name: String = _
var age : Int = _
println("1.父类主构造器")
def this(name: String, age: Int){
this()
println("2. 父类辅助构造器调用")
this.name = name
this.age = age
}
def printlnInfo(): Unit = {
println(s"Person: $name $age")
}
}
class Student(name: String, age: Int) extends Person {
var stdNo: String = _
println("3.子类主构造器")
def this(name: String, age: Int, stdNo: String) {
this(name, age)
println("4. 子类的辅助构造器")
this.stdno = stdNo
}
override def printInfo(): Unit = {
println(s"Person: $name $age $stdNo")
}
}
多态
在Java中 属性是静态绑定的
// Java
class Person{
String name = "person";
public void hello(){
System.out.println("hello person")
}
}
class Worker extends Person{
String name = "worker"
public void hello(){
System.out.println("hello worker")
}
public void hi(){
System.out.println("hi worker")
}
}
public class Test{
public static void main(String[] args){
Person person = new Worker()
person.name // person 静态绑定
person.hello() // hello worker 动态绑定
person.hi() //error
}
}
- Scala中更加彻底,属性也是动态绑定
```scala
object Test {
def main(args: Array[String]): Unit = {
println(student.name) // student student.hello() // hello student } }val student: Person = new Student
class Person { var name: String = “person” def hello(): Unit = { println(“hello person”) } }
class Student extend Person { var name: String = “student” override def hello(): Unit = { println(“hello student”) } }
<a name="zFKy7"></a>
## 抽象类
如果类中有抽象字段或抽象方法,那么该类就是一个抽象类
- 抽象字段:没有初始化值的变量
- 抽象方法:没有方法体的方法
<a name="T8RQ7"></a>
### 抽象类属性和抽象方法
<a name="yVatH"></a>
#### 基本语法
1. 定义抽象类: abstract class Person()
1. 定义抽象属性:val name: String //只有抽象属性没有初始化
1. 定义抽象方法:def hello(): String //只声明没有实现
- 只要出现抽象属性和方法必须是抽象类
- 抽象类可以有具体方法
<a name="zZ7Ub"></a>
#### 重写和继承
1. 如果父类为抽象类,那么子类需要将抽象的属性和方法实现,否则子类也需要声明为抽象类
1. 重写非抽象方法需要用override修饰,重写抽象方法可以不加
1. 子类中调用父类的方法使用super关键字
1. 子类对抽象属性进行实现,父类抽象属性可以用var修饰
子类对非抽象属性进行重写,父类非抽象属性只支持val类型,而不支持var,因为var修饰符为可变变量,子类继承之后就可以直接使用,没有必要重写
```scala
object Test {
def main(args: Array[String]): Unit = {
val student = new Student
student.eat() // person eat student eat
student.sleep() //student sleep
}
}
// 定义抽象类
abstract class Person{
// 非抽象属性
val name: String = "person"
// 抽象属性
var age: Int
// 非抽象方法
def eat(): Unit = {
println("person eat")
}
// 抽象方法
def sleep(): Unit
// 非抽象方法
def eat(): Unit = {
println("person eat")
}
}
class Student extends Person {
var age: Int = 18
def sleep(): Unti = {
println("student sleep")
}
// 重写非抽象属性和方法,如果父类是var的,直接改就行了
override val name: String = "student"
override def eat(): Unit = {
super.eat()
println("student eat")
}
}
isInstanceOf & asInstanceOf
- isInstanceOf 判断是否为指定类型对象
- asInstanceOf将对象转换为指定类型 ```scala class Person
class Student extends Person { def sayHello(): Unit = { println(“Hello!”) } }
object Test02 { def main(args: Array[String]): Unit = { val person: Person = new Student if (person.isInstanceOf[Student]) person.asInstanceOf[Student].sayHello() } }
<a name="uEPAi"></a>
### getClass & classOf
- isInstanceOf只能判断出对象是否为指定类型及其子类的对象,而不能精准的判断出对象就是指定类的对象。如果要求精准的判断出指定数据类型,只能使用一下方法
- getClass可以精准获取对象的类型
- classOf[类名] 可以精准获取数据类型
- 使用==操作符可以直接比较类型
```scala
class Person2
class Student2 extends Person2 {
def sayHello(): Unit = {
println("Hello!")
}
}
object Test03 {
def main(args: Array[String]): Unit = {
val person: Person2 = new Student2
println(person.isInstanceOf[Person2]) //true
println(person.isInstanceOf[Student2]) // true
println(person.getClass == classOf[Person2]) //false
println(person.getClass == classOf[Student2]) //true
}
}
匿名内部类(抽象类型的子类)
使用场景:
- 成员方法只调用一次
- 可以作为方法的实际参数传递
如果匿名内部类的主构造器为空,小括号可以不写
object Test {
def main(args: Array[String]): Unit = {
// 1
val person: Person = new Person{
override var name: String = _
override def eat(): Unit = println("person eat1")
}.eat()
println(person.name)
// 2
def show(p:person) = p.eat()
val person2: Person = new Person{ //实际上是多态
override def eat(): Unit = println("person eat2")
}
show(person2)
}
}
// 定义抽象类
abstract class Person {
var name: String
def eat(): Unit
}
单例对象(伴生对象)
Scala语言完全面向对象,所以没有静态操作。但是为了能够和Java交互,就产生了一种特殊的对象来模拟类对象,该对象为单例对象。单例对象与类名一致,类所有静态内容都可以放置在它的半生对象中声明。
- 单例对象采用object关键字
- 单例对象对应的伴生类名称一样
- 单例对象的属性和方法都可以通过伴生对象名(类名)直接调用访问(private也可以) ```scala Object Test { def main(args: Array[String]): Unit = { val student = new Student(“alice”, 18) student.printInfo() } }
// 定义类 class Student(val name: String, val age: Int) { def printInfo() = { println(s”student: name = ${name}, age = $age, school = $Student.school”) } }
// 伴生对象 object Student { val school: String = “atg” }
<a name="Y1xaw"></a>
#### 伴生对象调用构造方法
```scala
Object Test {
def main(args: Array[String]): Unit = {
val student = Student.newStudent("alice",14)
val student2 = Student.apply("bob",18)
val student2 = Student("bob",18) // apply方法可以省略
student.printInfo()
}
}
// 定义类
class Student private(val name: String, val age: Int) { //构造器私有化
def printInfo() = {
println(s"student: name = ${name}, age = $age, school = $Student.school")
}
}
// 伴生对象
object Student {
val school: String = "atg"
// 定义了一个类的对象实例创建方法,包装好
def newStudent(name: String, age: Int): Student = new Student(name, age)
def apply(name: String, age: Int): Student = new Student(name, age)
}
- 对于伴生对象中的apply() 调用时可以省略 .apply
使用继承App特质的方式定义程序主入口
object Test extends App{
println("")
}
单例设计模式
```scala class Student private(val name: String, val age: Int) { //构造器私有化 def printInfo() = { println(s”student: name = ${name}, age = $age, school = $Student.school”) } }
// 饿汉式 object Student { private val student: Student = new Student(“alice”,12) def getInstance(): Student = student }
// 懒汉式 object Student2 { private var student: Student2 = _ def getInstance(): Student2 = { if (student == null) { // 如果没有实例的话,创建一个 student = new Student2(“alice”, 18) } student } }
object Test { def main(args: Array[String]): Unit = { val student1 = Student.getInstance() val student2 = Student.getInstance()
// 引用地址完全一样
println(student1)
println(student2)
} }
<a name="e2p75"></a>
## 特质(Trait)
Scala语言中,采用特质来代替接口,也就是说多个类具有相同特质时,就可以将这个特质独立出来,采用trait声明<br />Scala中trait可以有抽象属性和方法,**也可以有具体的属性和方法**,一个类可以混入多个特质,类似于Java中的抽象类
```scala
trait 特质名{
}
class 类名 extends 特质1 with 特质2 // 没有父类
class 类名 extends 父类 with 特质1 with 特质2 // 有父类
object Test {
def main(args: Array[String]): Unit = {
val student = new Student
student.sayHello()
student.study()
student.dating()
}
class Person {
val name: String = "person"
var age: Int = 18
def sayHello(): Unit = {
println("hello from:" + name)
}
}
trait Young{
// 声明抽象和非抽象属性
var age: Int
val name: String = "young"
// 非抽象方法
def play(): Unit = {
println("young people is playing")
}
// 抽象方法
def dating(): Unit
}
class Student extends Person with Young {
// 重写冲突的属性
override val name: String = "student"
def dating(): Unit = println(s"student $name is dating")
def study(): Unit = println(s"student $name is studying")
// 重写父类的方法
override def sayHello(): Unit = {
super.sayHello()
println(s"hello froms: student $name")
}
}
单例对象继承特质
object Test07 {
def main(args: Array[String]): Unit = {
ConsoleLogger.log("Success")
ConsoleLogger.warn("Warning")
}
}
trait Logger {
def log(msg: String)
}
trait Waring {
def warn(msg: String)
}
object ConsoleLogger extends Logger with Waring {
override def log(msg: String) = println(s"Log: $msg" )
override def warn(msg: String): Unit = println(s"Warn: $msg")
}
特质的混入
object Test {
def main(args: Array[String]): Unit = {
val student = new Student
student.study()
student.increase()
// 动态混入:让某个对象临时可以访问某个特质中的成员
val studentWithTalent = new Student with Talent {
override def dancing(): Unit = println("dancing")
override def singing(): Unit = println("singing")
}
studentWithTalen.dancing()
}
}
trait Talent {
def singing(): Unit
def dancing(): Unit
}
// 再定义一个特质
trait Knowledge {
var amount: Int = 0
def increase(): Unit
}
class Student extends Person with Young with Knowledge {
// 重写冲突的属性
override val name: String = "student"
def dating(): Unit = println(s"student $name is dating")
def study(): Unit = println(s"student $name is studying")
// 重写父类的方法
override def sayHello(): Unit = {
super.sayHello()
println(s"hello froms: student $name")
}
override def increase()L Unit = {
amount += 1
println(s"student $name knowledge increase $amount")
}
}
特质叠加
trait Talent{
def dancing(): Unit
def increase(): Unit = println("talent increase")
}
trait Knowledge{
def dancing(): Unit
def increase(): Unit = println("knowledge increase")
}
class Student extend Person with Talent with Knowledge {
override def dancing(): Unit = println("dancing")
override def increase(): Unit = {
super.increase() // konwledge increase
}
}
- 优先使用特质,一个类扩展多个特质是方便的,但只能扩展一个抽象类
- 如果需要构造函数,使用抽象类。因为抽象类可以定义带参数的构造函数,而特质不行
特质自身类型
```scala object Test { def main(args: Array[String]): Unit = { var user = new Register(“alice”, 12345) user.insert() } }
class User(val name: String, val password: String)
trait UserDao { // 想要拥有User的属性又不想继承User _: User => // 将自身类指定为User 依赖注入
// 向数据库插入数据 def insert(): Unit = { println(s”insert into db: ${this.name}”) } }
// 定义注册用户类 class RegisterUser(name: String, password: String) extends User(name, password) with UserDao {}
<a name="ND1Kp"></a>
### 使用trait实现适配器模式
设计模式是前辈们对代码开发经验的总结,用来提高代码可复用性、可维护性、可读性、稳健性、安全性
<a name="sSC5U"></a>
#### 分类:
1. 创建型:单例模式,工厂方法
1. 结构型:类、特质之间的关系架构,适配器模式,装饰模式
1. 行为型:类能够做什么,模板方法模式,职责链模式
<a name="nAjXu"></a>
#### 适配器模式
当特质中有多个抽象方法,而我们只需要其中的某一个或某几个方法时,不得不将该特质中的所有抽象方法重写,这样很麻烦。我们可以定义一个抽象类去继承该特质,重写特质中的抽象方法,方法体为空。这时候我们需要哪个方法只需要定义类继承抽象类,重写指定方法即可,这个抽象类就叫做适配器类
```scala
object Test01 {
def main(args: Array[String]): Unit = {
val greenHand = new GreenHand
greenHand.support()
greenHand.schoolchild()
}
}
trait PlayLOL {
def top()
def mid()
def adc()
def support()
def jungle()
def schoolchild()
}
abstract class Play extends PlayLOL {
override def top(): Unit = ???
override def mid(): Unit = ???
override def adc(): Unit = ???
override def support(): Unit = ???
override def jungle(): Unit = ???
override def schoolchild(): Unit
}
class GreenHand extends Play {
override def support() = {
println("support")
}
override def schoolchild() = {
println("schoolchild")
}
}
模板方法
扩展性更强,符合开闭原则
abstract class Template {
// 记录获取时间
def code()
// 具体规则
def getRuntime() = {
val start = System.currentTimeMillis()
code()
val end = System.currentTimeMillis()
end - start
}
}
class ForDemo extends Template {
override def code(): Unit = for(i <- 1 to 10000) println("say hello")
}
def main(args: Array[String]): Unit = {
val fd = new ForDemo
println(fd.getRuntime())
}
样例类
case class 样例类(val/var 成员变量名:类型 …) val/var 如果不写默认是val , 括号不能省
样例类中默认的方法
- apply() 让我们快速使用类名创建对象,省去new关键字
- toString() 打印对象属性
- equals() 可以让我直接用==判断对象成员变量值
- hasCode() 用来获取对象的哈希值,同一对象哈希值相同
copy() 可以快速创建一个属性值相同的实例对象,还可以使用带名参数赋值 ```scala object Test02 { def main(args: Array[String]): Unit = { val p1 = Person(“李四”, 24) // 因为有apply方法所以省略new
println(p1) // 默认调用类toString方法
val p2 = Person(“李四”, 24)
println(p1 == p2) // equals()让我们可以用==比较对象的属性
// 同一对象哈希值肯定相同,不同对象哈希值一般不同,下面相同 println(p1.hashCode()) println(p2.hashCode())
// 基于一个对象快速构建另一个对象 val p3 = p2.copy(age = 35) println(p3) } }
case class Person(name: String = “张三”, var age: Int = 23)
```scala
// 计算器样例
object Test04 {
def main(args: Array[String]): Unit = {
val c = Calculate(3, 2)
println(c.add()) //5
}
}
case class Calculate(a: Int, b: Int) {
def add() = a + b
def subtract() = a - b
def multiply () = a * b
def divide() = a / b
}
样例对象
用case修饰,没有主构造器
- 当作枚举值使用:固定值用于统一规范
- 作为没有任何参数的消息传递 ```scala object Test03 { def main(args: Array[String]): Unit = { val person = Person03(“张三”, Male) println(person.name, person.sex) //(张三,Male) } }
trait Sex {
}
case object Male extends Sex
case object Female extends Sex
case class Person03(var name: String, var sex: Sex)
<a name="DTIjE"></a>
### trait构造机制
```scala
trait Logger {
println("执行Logger构造器")
}
trait MyLogger extends Logger{
println("执行MyLogger构造器")
}
trait TimeLogger extends Logger {
println("执行TimeLogger构造器")
}
class Person {
println("执行Person构造器")
}
class Student extends Person with MyLogger with TimeLogger {
println("执行Student类构造器")
}
def main(args: Array[String]): Unit = {
val student = new Student
/**
1 执行Person类构造器
2 执行Logger构造器
3 执行MyLogger构造器
4 执行TimeLogger构造器
5 执行Student类构造器
*/
}
案例:程序员类
class Programeer {
var name: String = _
var age: Int = _
def eat() {}
def skill() {}
}
trait BigData {
def learningBigDate() {
println("learnint bigdata")
}
}
class JavaProgrammer extends Programmer {
override eat() {
println("Java eat")
}
override skill() {
println("Java skill")
}
}
class PythonProgrammer extends Programmer {
override eat() {
}
override skill(){
}
}
class PartJavaProgrammer extends JavaProgrammer with BigData {
override eat() {
}
override skill(){
super.skill()
learningBigData()
}
}
class PartPythonProgrammer extends PythonProgrammer with BigData {
override eat() {
}
override skill(){
super.skill()
learningBigData()
}
}
object Test {
def main(args: Array[String]): Unit = {
val jp = new JavaProgrammer
jp.name = "zhangsan"
jp.age = 23
jp.skll()
jp.eat()
val pjp = new PartJavaProgrammer
pjp.name = "666"
pjp.age = 23
pjp.skill()
}
}
Object Test {
def main(args: Array[String]): Unit = {
// 创建二维数组
val array: Array[Array[Int]] = Array.ofDim[Int](2,3)
// 访问元素
array(0)(2) = 19
array(1)(0) = 25
println(array.mkString(", "))
for (i <- 0 until array.length; j <- 0 until array(i).length) {
println(array(i)(j))
}
for ( i <- array.length; j <- array(i).indices) {
print(array(i)(j) + "\t")
if (j == array(i).length -1) println()
}
array.foreach(line => line.foreach(println))
array.foreach(_.foreach(println))
}
}