1. 对象(object) 在scala 中被object 关键字修饰的类有一下特征
没有 有参数的主构造器, 但是有主构造器代码块(不包含在任何方法中的代码,就是主构造器代码)
它是单例的所以主构造器代码块只会执行一次
不需要通过关键字 new 创建对象,直接通过类名创建对象
通常用于封装一些常量,工具类,枚举和隐式转换函数
1.1 对象的定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 object ObjectDemo1 { def main (args: Array [String ]): Unit = { println("ObjectDemo1 的主构造器代码块1" ) def sayHello = println("hello ! " ) } } object ObjectDemo1_1 { def main (args: Array [String ]): Unit = { val o1 = ObjectDemo1 val o2 = ObjectDemo1 println(o1.hashCode() == o2.hashCode()) } } object ObjectDemo1_2 extends App { println("ObjectDemo1_2 的主构造器代码块1" ) }
1.2 对象作为枚举类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 object ObjectDemo2 extends App { println(MyEnum .WOLF ) println(MyEnum .withName("Wolf" )) val values:MyEnum .ValueSet = MyEnum .values values.foreach(println) println(MyEnum (0 )) } object MyEnum extends Enumeration { val WOLF = Value (0 ,"Wolf" ) println(s"WOLF=$WOLF " ) val DOG = Value (1 ,"dog" ) println(s"DOG=$DOG " ) val CAT = Value (2 ,"cat" ) println(s"CAT=$CAT " ) }
2. 类(class) 类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间。类是用于创建对象的蓝图,它是一个定义包括在特定类型的对象中的方法和变量的软件模板。
2.1 类的定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class Class1 { val name:String = "class1" var age:Int =15 val country = "China" private [this ] val color="red" def getColor= { color } def email = { name + "@mail.com" } } private [classpag] class Class2 { val name:String = "class2" } val c1 = new Class1 println(c1.country) println(c1.getColor) println(c1.email)
2.2 类的构造器(构造方法) 在scala 中类的构造器分为两种
主构造器:与类名交织在一起,一个类只能定义一个主构造器
创建对象的顺序一定是主构造器最先执行
主构造器的参数会成为类的字段属性
在主构造器参数中,没有被任何关键字修饰的参数,默认为private [this] var/val
不包含在任何方法中的代码,就是主构造器的代码
辅助构造器:辅助构造器可以定义多个
辅助构造器的第一行代码必须调用主构造器
创建对象的顺序一定是主构造器最先执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 class Class3 ( val name:String , var age:Int , height:Int , private var brothday2:String , var color:String ="blue" ) { println("这是主构造器的代码" ) var sex:String ="" println(s"print in Class3 height= ${this.height} " ) def this (name:String ,age:Int ){ this (name,age,170 ,null ,null ) this .sex = "男" println("辅助构造器1" ) } def this (name:String ){ this (name,16 ) this .brothday2="birthday2" println("辅助构造器2" ) } } object ClassDemo2 { def main (args: Array [String ]): Unit = { val c3 = new Class3 ("xiaom" ,18 ,180 ,"birthday" ) println("name=>" +c3.name) println("age=>" +c3.age) println("color=>" +c3.color) println("sex=>" +c3.sex) val c3_1 = new Class3 ("xiaob" ,19 ) println("name=>" +c3_1.name) println("age=>" +c3_1.age) println("color=>" +c3_1.color) println("sex=>" +c3_1.sex) val c3_2 = new Class3 ("xiaos" ) println("name=>" +c3_2.name) println("age=>" +c3_2.age) println("color=>" +c3_2.color) println("sex=>" +c3_2.sex) } }
3. 伴生类与伴生对象
定义:
在同一个**scala的类文件中**
如果**class和object的名字相同**
那么class是object的伴生类
object是class的伴生对象
特点:
伴生类与伴生对象可以互相访问被关键字private修饰的字段,需要注意的是**被private this 修饰的对象或属性不能访问**
可以通过伴生类与伴生对象创建对象
创建伴生类与伴生对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class ClassDemo4 { private val name:String = "xiaom" private [this ] var tel:String = "15000000000" def getTel () = { this .tel } def setTel (tel:String ): Unit ={ this .tel = tel } } object ClassDemo4 { def main (args: Array [String ]): Unit = { val c4 = new ClassDemo4 println(c4.name) c4.setTel("new number" ) println(c4.getTel()) } } object ClassDemo4_1 { def main (args: Array [String ]): Unit = { val c4 = new ClassDemo4 } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class MyArray { private var name:String = "小明" println(MyArray .name) } object MyArray { private var name:String = "小红" println(new MyArray ().name) def apply (nums:Int *):Array [Int ] = { println("apply(nums:Int*)" ) val arr = new Array [Int ](nums.length) for (i<- 0 to nums.length -1 ){ arr(i) = nums(i) } arr } } object ObjectDemo05 { def main (args: Array [String ]): Unit = { var myarr1 = MyArray (5 ) var myarr2 = new MyArray () } }
3.1 apply 方法 当对象(伴生对象)以函数的方式进行调用时,scala 会隐式地将调用改为在该对象上调用apply方法。 Scala 的apply有2张形式,一种是伴生对象的apply,一种是伴生类中的apply。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 object ClassDemo5 { println("hello world" ) def apply ():String ={ println("apply() in object" ) "hello" } def apply (nums:Int *):ArrayBuffer [Int ]={ println("apply(nums:Int*)" ) val arr = new ArrayBuffer [Int ]() nums.map(arr.append(_)) arr } } class ClassDemo5 { def apply () = println("apply in class" ) def say : Unit = { println("say Hello apply in class" ) } } object ClassDemo5_1 extends App { val c5 = ClassDemo5 () println(c5.hashCode()) val c5_1 = ClassDemo5 (1 ,2 ,3 ,4 ,5 ) println(c5_1.toBuffer) println(c5_1.hashCode()) val c5_2 = new ClassDemo5 () c5_2.say }
3. 内部类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Persion { class Student val listBuffer = ListBuffer [Persion #Student ]() def getStudent :Student ={ new Student } } object ObjectDemo08 { def main (args: Array [String ]): Unit = { val p1 = new Persion val s1 = p1.getStudent p1.listBuffer += s1 val p2 = new Persion val s2 = p2.getStudent } }
4. 匿名类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 object ClassDemo6 { def main (args: Array [String ]): Unit = { new ClassDemo6 { override def sayHello (): Unit = { println("hello ClassDemo6 的匿名类" ) } }.sayHello() val a = new ClassDemo6_1 ("小明" ,12 ){ override def say : Unit = { println(s"hello ClassDemo6_1 匿名类 $name $age " ) } } a.say val b = new ClassDemo6_1 ("小明" ,12 ) println(a.getClass) println(b.getClass) } }
5. 抽象类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 object ClassDemo8 { def main (args: Array [String ]): Unit = { val c8 = new ClassDemo8 ("xiaom" ,18 ) c8.sayHello } } abstract class ClassDemo8_1 { def sayHello // 抽象方法 val name: String var age: Int val id = 1001 var number = 1001 } class ClassDemo8 (val n:String ,val a:Int ) extends ClassDemo8_1 { override def sayHello : Unit = { println(s"hello $name " ) } override val name: String = n override var age: Int = a number = 1002 }
6. 样例类(case class) scala 中被case修饰的类被称为样例类样例类和普通的类基本一致只是可以不使用new 关键字来创建对象
特点:
新建类实例不用new
自动定义好getXX方法,
提供默认的toString()
结合类继承可以通过模式匹配进行分解
6.1 样例类的定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 object ClassDemo7 { def main (args: Array [String ]): Unit = { val c7 = ClassDemo7_1 ("xioam" ,12 ) println(c7.name) println(c7.howOld()) println(c7.toString) val c7_1 = ClassDemo7_1 ("xioam" ,12 ) } } case class ClassDemo7_1 (name:String ,age:Int ) { def howOld (): Int ={ age } }
6.2 样例类结合模式匹配 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Amimal case class Cat (age: Int ) extends Amimal case class Dog (age: Int , name: String ) extends Amimal object ClassDemo7_1 { def main (args: Array [String ]): Unit = { println(f(Cat (5 ))) println(f(Dog (3 , "dahuang" ))) } def f (t: Amimal ) = t match { case Cat (x) => "cat age = " + x case Dog (x, y) => y + " age = " + x } }
6.3 样例类代替tuple 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 case class Dog (age: Int , name: String ) object ClassDemo7_2 { def main (args: Array [String ]): Unit = { val p1 = (20 ,"dahuang" ) println(p1._1) println(p1._2) val p2 = Dog (20 ,"dahuang" ) println(p2.age) println(p2.name) } }
6.4 普通类与样例类的区别 在Scala中存在case class,它其实就是一个普通的class。但是它又和普通的class略有区别,如下:
初始化的时候可以不用new,当然你也可以加上,普通类一定需要加new;
1 2 3 4 5 6 7 8 9 scala> case class Student (name:String ) defined class Student scala> val stu = Student ("xiaoming" ) stu: Student = Student (xiaoming) scala> val stu2 = new Student ("xiaohong" ) stu2: Student = Student (xiaohong)
toString的实现更漂亮;
1 2 3 scala> stu res5: Student = Student (xiaoming)
默认实现了equals 和hashCode;
1 2 3 4 5 scala> val stu3 = new Student ("xiaohong" ) stu2: Student = Student (xiaohong) scala> stu3 == stu2 res6: Boolean = true
默认是可以序列化的,也就是实现了Serializable ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 scala> class A defined class A scala> import java.io._ import java.io._ scala> val bos = new ByteArrayOutputStream bos: java.io.ByteArrayOutputStream = scala> val oos = new ObjectOutputStream (bos) oos: java.io.ObjectOutputStream = java.io.ObjectOutputStream @4 c257aef scala> oos.writeObject("xiaoming" ) scala> val a = new A a: A = $iwC$$iwC$A @71687 b10 scala> oos.writeObject(a) java.io.NotSerializableException : $iwC$$iwC$A
自动从scala.Product中继承一些函数;
case class构造函数的参数是public级别的,我们可以直接访问;
1 2 3 scala> stu.name res11: String = xiaoming
支持模式匹配;
其实感觉case class最重要的特性应该就是支持模式匹配。这也是我们定义case class的唯一理由,难怪Scala官方也说:It makes only sense to define case classes if pattern matching is used to decompose data structures. 。来看下面的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 object TermTest extends scala .App { def printTerm (term: Term ) { term match { case Var (n) => print(n) case Fun (x, b) => print("^" + x + "." ) printTerm(b) case App (f, v) => print("(" ) printTerm(f) print(" " ) printTerm(v) print(")" ) } } def isIdentityFun (term: Term ): Boolean = term match { case Fun (x, Var (y)) if x == y => true case _ => false } val id = Fun ("x" , Var ("x" )) val t = Fun ("x" , Fun ("y" , App (Var ("x" ), Var ("y" )))) printTerm(t) println println(isIdentityFun(id)) println(isIdentityFun(t)) }
7. 继承(extends)
如果子类继承的父类是抽象类,那么要实现父类中所有未实现的方法与字段。
当子类重写父类的非抽象字段时,父类中该字段不能用val 修饰否则会报异常。
父类中抽象字段不能使用private修饰,因为抽象字段本身就是需要子类去实现的,如果添加private关键字,那么子类无法访问,则抛异常
子类重写父类的非抽象方法时必须要添加 override 关键字,如果需要指明调用父类的方法,需要使用supper.say()方法
子类继承父类后,在创建子类的实例对象时,会先初始化父类的构造函数,然后执行子类自己的构造函数
如果子类的构造函数和父类的构造函数,接收的参数名字是一样的,那么子类的相同的参数名字就不能添加任何关键字进行修饰,否则scala会认为子类要重写父类的字段
7.1 继承示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class Animal { println("Animal 的主构造器代码" ) def say= { println("hello" ) } } class Dog extends Animal { println("Dog 的主构造器代码" ) override def say : Unit = { println("hello 汪汪" ) } } class Cat extends Animal { println("Cat 的主构造器代码" ) override def say : Unit = { println("hello 喵喵" ) } } object ExtendsDemo1 { def main (args: Array [String ]): Unit = { val dog = new Dog dog.say val cat = new Cat cat.say } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 abstract class ExtendsDemo3_1 { val name:String val age:Int = 18 def sayHello (context:String ) def say (context:String )={ println("say " +context) } } class ExtendsDemo3 extends ExtendsDemo3_1 { override val name: String = "小明" override val age = 12 override def sayHello (context: String ): Unit = { println("say hello " +context) } override def say (context: String ) = { super .say(context) } }
7.3 匿名类的继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 object ClassDemo6 { def main (args: Array [String ]): Unit = { new ClassDemo6 { override def sayHello (): Unit = { println("hello ClassDemo6 的匿名子类" ) } }.sayHello() val a = new ClassDemo6_1 ("小明" ,12 ){ override def say : Unit = { println(s"hello ClassDemo6_1 的匿名子类 $name $age " ) } } a.say val b = new ClassDemo6_1 ("小明" ,12 ) println(a.getClass) println(b.getClass) } } abstract class ClassDemo6 { def sayHello ()={ println("helo" ) } } class ClassDemo6_1 (var name:String , var age:Int ) { def say= { println(s"hello $name $age " ) } }
7.2 isInstanceOf / asInstanceOf
isInstanceOf 用来判断实例对象是否是指定类及其子类, 那么意味着isInstanceOf 不能做精确判断
asInstanceOf 用来将对象转换成其他类型,在用asInstanceOf 之前,应该使用isInstanceOf 先做判断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 object ExtendsDemo1_1 { def main (args: Array [String ]): Unit = { val dog:Any = new Dog println(s"dog.isInstanceOf[Animal]=${dog.isInstanceOf[Animal]} " ) if (dog.isInstanceOf[Animal ]){ val d = dog.asInstanceOf[Animal ] d.say } val cat = new Cat println(cat.getClass == classOf[Cat ]) } }
8. 特质(Trait)
在scala中triat是一种特殊概念,triat的用途有很多,可以作为类似java中的interface接口使用
类可以支持对triat的多重继承,继承的时候统一使用extends关键字,多继承时使用with关键字
8.1 特质的定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 trait TraitDemo1_1 { def say (content:String ):Unit val name:String = "小明" var name2:String = "小红" val age:Int } trait TraitDemo1_2 { def sayHello (content:String ):Unit } class TraitDemo1_3 extends TraitDemo1_1 with TraitDemo1_2 { def say (content: String ): Unit = { println(content) } override def sayHello (content: String ): Unit = { println(s"hello $content " ) } name2 = "xiaoh" override val age: Int = 10 } object TraitDemo1 { def main (args: Array [String ]): Unit = { val t = new TraitDemo1_3 t.say("hello" ) t.sayHello("xiaom" ) } }
8.2 特质的构造函数 继承了类和Trait的构造机制如下
执行父类的构造代码块
执行Trait的构造代码块,如果继承多个Trait 那么从左往右执行Trait的构造代码块
如果多个Trait继承了同一个Trait,那么限制性父Trait的构造代码块,然后再执行子Trait的构造代码块
父Trait的构造代码块只会执行一次
最后执行自己的构造代码块,即子类的构造代码块最后执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 trait TraitDemo2_1 { println("TraitDemo2_1 的主构造代码块" ) } trait TraitDemo2_2 extends TraitDemo2_1 { println("TraitDemo2_2 的主构造代码块(extends trait)" ) } trait TraitDemo2_3 extends TraitDemo2_1 { println("TraitDemo2_3 的主构造代码块(extends trait)" ) } class TraitDemo2_4 { println("TraitDemo2_4 的主构造代码块(extends class)" ) } class TraitDemo2_5 extends TraitDemo2_4 with TraitDemo2_2 with TraitDemo2_3 { println("TraitDemo2_5 的主构造代码块" ) } object TraitDemo2 { def main (args: Array [String ]): Unit = { val s = new TraitDemo2_5 } }
8.3 在实体类中混入特质 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 trait TraitDemo3_1 { def say : Unit ={ println("hello" ) } } class TraitDemo3_2 (var name:String ,var age:Int )object TraitDemo3 { def main (args: Array [String ]): Unit = { val b1 = new TraitDemo3_2 ("小明" ,1 ) val b2 = new TraitDemo3_2 ("小明" ,1 ) with TraitDemo3_1 b2.say } }