特质(trait)
特质(scala)和接口(java)的异同点:
相同点:
- scala中的特质类似java中的接口(没有任何具体方法的时候),某个类可以实现多个特质。
不同点:
- 特质可以有默认方法实现
- 子类实现特质用
extends
关键字;实现接口用implements
- 实现多个特质时,中间用
with
连接;实现多个接口时,中间用,
分割
scala版本
ConsoleLogger.scala1 2 3
| class ConsoleLogger extends Logger with Cloneable with Serializable { }
|
java版本
ConsoleLogger.java1 2 3
| class ConsoleLogger implements Logger,Cloneable,Serializable { }
|
JDK 8是否也有类似?
构造不可修改数据类
不可修改的数据类有各种好处:
- 不用担心线程安全
- 方便定位问题
- 对象一旦被创建,就不用担心数据被错误修改
Java语言实现不可变数据类主要有2种方法:
- 只有构造函数和getter的类
- 使用
Builder
模式
方法1的主要问题在于:如果类的成员变量有多个(例如大于3个),而且不是必选的话,需要重载多个构造函数,在使用的时候容易造成混乱。
方法2主要可参见《Effective Java 2nd Edition》的第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 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
| public class ImmutableObject { private final int a; private final int b; private final int c; private final int d; private final int e; private ImmutableObject(Builder builder) { this.a = builder.a; this.b = builder.b; this.c = builder.c; this.d = builder.d; this.e = builder.e; } @Override public String toString() { return "ImmutableObject{" + "a=" + a + ", b=" + b + ", c=" + c + ", d=" + d + ", e=" + e + '}'; } public static class Builder { private final int a; private final int b; private int c = 1; private int d = 2; private int e = 3; public Builder(int a, int b) { this.a = a; this.b = b; } public Builder c(int c) { this.c = c; return this; } public Builder d(int d) { this.d = d; return this; } public Builder e(int e) { this.e = e; return this; } public ImmutableObject build() { return new ImmutableObject(this); } } public static void main(String[] args) { ImmutableObject obj = new Builder(10, 20) .c(30) .d(40) .build(); System.out.println(obj); } }
|
输出结果为:
1
| ImmutableObject{a=10, b=20, c=30, d=40, e=3}
|
scala语言实现有3种方案
- Immutable Classes
- Case Classes
- Tuples
Immutable Class:将类的主构造函数中的参数都设为val
,还可以设置参数的默认值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class ImmutableScalaClass( val a:Int, val b:Int, val c:Int = 1, val d:Int = 2, val e:Int = 3) { override def toString = s"ImmutableScalaClass(a=$a, b=$b, c=$c, d=$d, e=$e)" } object ImmutableScalaObject { def main(args: Array[String]): Unit = { val obj = new ImmutableScalaClass( a = 10, b = 20, c = 30, d = 40 ) print(obj) } }
|
输出:
1
| ImmutableScalaClass(a=10, b=20, c=30, d=40, e=3)
|
可以看出,scala的语法比java的Builder模式要清晰和直观很多
Case Classes: 将类设为case class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| case class CaseScalaClass( val a: Int, val b: Int, val c: Int = 1, val d: Int = 2, val e: Int = 3) object CaseScalaObject { def main(args: Array[String]): Unit = { val obj = new CaseScalaClass( a = 10, b = 20, c = 30, d = 40 ) print(obj) } }
|
输出:
1
| CaseScalaClass(10,20,30,40,3)
|
由于case class默认实现了toString
、equals
、hashCode
等方法,所以写法更简洁
Tuples
1 2 3 4 5 6 7
| object TupleDemo { def main(args: Array[String]): Unit = { val t = (1, 2, 3, 4, 5) print(t._1, t._2, t._3, t._4, t._5) } }
|
输出:
可以看出,Tuple
不用创建新的类,使用简单,当然用途也很单一,单纯作为一个容器使用
主构造函数
函数与过程
函数:有返回值的方法,格式为:
1 2 3
| def fuc(x: Int):Int = { ...... }
|
过程:没有返回值(或者说返回值类型为Unit
)的函数
1 2 3 4 5 6 7 8 9
| def fuc(x: Int) { ...... } 或者 def fuc(x: Int):Unit = { ...... }
|
闭包
可以简单理解成:闭包就是用函数创建函数,创建时用到的参数或者外部变量,在结果函数中都会保存它们的引用
例子:scala实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| object ClosureFunctionDemo { def makeClosureFunction(x: Int, func: Int => String) = { i: Int => func(x * i) } def baseFunction(i: Int): String = { "This is string: " + i } def main(args: Array[String]): Unit = { val closureFunction = makeClosureFunction(100, baseFunction) print(closureFunction(10)) } }
|
java实现
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
| public class JavaClosureFunction { public static void main(String[] args) { BaseFunction baseFunction = new BaseFunction() { @Override public String call(int i) { return "This is string: " + i; } }; */ BaseFunction baseFunction = i -> "This is string: " + i; ClosureFunction closureFunction = makeClosureFunction(100, baseFunction); System.out.println(closureFunction.call(10)); } private static ClosureFunction makeClosureFunction(int i, BaseFunction baseFunction) { return new ClosureFunction() { @Override public String call(int x) { return baseFunction.call(x * i); } }; */ return x -> baseFunction.call(x * i); } } public interface BaseFunction { String call(int i); } public interface ClosureFunction { String call(int i); }
|