在scala中,类的声明有 trait
, class
, object
三种。其中trait
声明接口,class
为一般类的声明,object
声明的类中的属性与方法都为静态,且在scala中没有static
关键字。
接口的定义-trait
trait
是接口类的声明,在scala中没有public
关键字,因为没有指定为protected
或private
的对象或方法都是为public
的,这一点与java不同。当trait
中所有的方法都没有实现时,反编译其编译出的.class
文件可知该类其实是一个abstract interface
:1
2
3trait Walking {
def walk(from: String, end: String): Unit
}
使用scalac Walking.scala
编译成.class
,通过jd-gui
反编译.class
出的内容为:1
2
3
4
5
6
7import scala.reflect.ScalaSignature;
"\006\001\0312q!\001\002\021\002G\005QAA\004XC2\\\027N\\4\013\003\r\tq\001P3naRLhh\001\001\024\005\0011\001CA\004\013\033\005A!\"A\005\002\013M\034\027\r\\1\n\005-A!AB!osJ+g\rC\003\016\001\031\005a\"\001\003xC2\\GcA\b\023?A\021q\001E\005\003#!\021A!\0268ji\")1\003\004a\001)\005!aM]8n!\t)BD\004\002\0275A\021q\003C\007\0021)\021\021\004B\001\007yI|w\016\036 \n\005mA\021A\002)sK\022,g-\003\002\036=\t11\013\036:j]\036T!a\007\005\t\013\001b\001\031\001\013\002\007\025tG\rC\003#\001\031\0051%\001\003uC2\\GCA\b%\021\025)\023\0051\001\025\003\0259xN\0353t\001") (bytes=
public abstract interface Walking
{
public abstract void walk(String paramString1, String paramString2);
}
当trait
声明的类中存在实现的方法时,其反编译的.class
对象将会包含一个静态初始化方法:1
2
3
4
5
6
7trait Walking {
def walk(from: String, end: String): Unit
def talk(words: String): Unit = {
printf("talk %s.", words)
}
}
反编译内容为:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import scala.Predef.;
import scala.reflect.ScalaSignature;
"\006\001%2q!\001\002\021\002\007\005QAA\004XC2\\\027N\\4\013\003\r\tq\001P3naRLhh\001\001\024\005\0011\001CA\004\013\033\005A!\"A\005\002\013M\034\027\r\\1\n\005-A!AB!osJ+g\rC\003\016\001\021\005a\"\001\004%S:LG\017\n\013\002\037A\021q\001E\005\003#!\021A!\0268ji\")1\003\001D\001)\005!q/\0317l)\ryQC\t\005\006-I\001\raF\001\005MJ|W\016\005\002\031?9\021\021$\b\t\0035!i\021a\007\006\0039\021\ta\001\020:p_Rt\024B\001\020\t\003\031\001&/\0323fM&\021\001%\t\002\007'R\024\030N\\4\013\005yA\001\"B\022\023\001\0049\022aA3oI\")Q\005\001C\001M\005!A/\0317l)\tyq\005C\003)I\001\007q#A\003x_J$7\017") (bytes=
public abstract interface Walking
{
public abstract void walk(String paramString1, String paramString2);
public void talk(String words)
{
Predef..MODULE$.printf("talk %s.", Predef..MODULE$.genericWrapArray(new Object[] { words }));
}
public static void $init$(Walking $this) {}
}
注意 这里在
import
语句中有import scala.Predef.;
当tracit
中包含属性或语句块时,其声明的属性getter/setter方法都会是abstract
方法,有默认值则在静态初始方法$init$
中赋值,trait
中的语句块都在$init$
静态方法中执行。1
2
3
4
5
6
7
8
9
10
11trait Walking {
def walk(from: String, end: String): Unit
var name: String = "hero"
val alias: String = "HERO"
println("this is a trait named Walking.")
println(name)
println(alias)
// alias = "NEW HERO" // 报错, val声明的属性不可变更, 即使在其反编译内容中含有setter方法(Walking$_setter_$alias_$eq)
}
其反编译结果为: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
26import scala.Predef.;
import scala.reflect.ScalaSignature;
"\006\00192q!\001\002\021\002\007\005QAA\004XC2\\\027N\\4\013\003\r\tq\001P3naRLhh\001\001\024\005\0011\001CA\004\013\033\005A!\"A\005\002\013M\034\027\r\\1\n\005-A!AB!osJ+g\rC\003\016\001\021\005a\"\001\004%S:LG\017\n\013\002\037A\021q\001E\005\003#!\021A!\0268ji\")1\003\001D\001)\005!q/\0317l)\ryQC\t\005\006-I\001\raF\001\005MJ|W\016\005\002\031?9\021\021$\b\t\0035!i\021a\007\006\0039\021\ta\001\020:p_Rt\024B\001\020\t\003\031\001&/\0323fM&\021\001%\t\002\007'R\024\030N\\4\013\005yA\001\"B\022\023\001\0049\022aA3oI\"9Q\005\001a\001\n\0031\023\001\0028b[\026,\022a\006\005\bQ\001\001\r\021\"\001*\003!q\027-\\3`I\025\fHCA\b+\021\035Ys%!AA\002]\t1\001\037\0232\021\035i\003A1A\005\002\031\nQ!\0317jCN\004") (bytes=
public abstract interface Walking
{
public abstract void Walking$_setter_$alias_$eq(String paramString);
public abstract void walk(String paramString1, String paramString2);
public abstract String name();
public abstract void name_$eq(String paramString);
public abstract String alias();
public static void $init$(Walking $this)
{
$this.name_$eq("hero");
$this.Walking$_setter_$alias_$eq("HERO");
Predef..MODULE$.println("this is a trait named Walking.");
Predef..MODULE$.println($this.name());
Predef..MODULE$.println($this.alias());
}
}
注意 以上实例在jdk8环境下使用jd-gui
类的定义-class
使用class
声明类,实现trait
声明的接口:1
2
3
4
5
6
7
8
9
10class MyWalking extends Walking {
override def walk(from: String, end: String): Unit = {
printf("walk from %s to %s.", from, end)
}
def test(): Unit = {
name = "NEW NAME"
printf("new name is %s, alias is %s.", name, alias)
}
}
MyWalking
反编译结果为: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
46import scala.Predef.;
import scala.reflect.ScalaSignature;
"\006\00112A!\001\002\001\013\tIQ*_,bY.Lgn\032\006\002\007\0059A(Z7qift4\001A\n\004\001\031a\001CA\004\013\033\005A!\"A\005\002\013M\034\027\r\\1\n\005-A!AB!osJ+g\r\005\002\016\0355\t!!\003\002\020\005\t9q+\0317lS:<\007\"B\t\001\t\003\021\022A\002\037j]&$h\bF\001\024!\ti\001\001C\003\026\001\021\005c#\001\003xC2\\GcA\f\033OA\021q\001G\005\0033!\021A!\0268ji\")1\004\006a\0019\005!aM]8n!\tiBE\004\002\037EA\021q\004C\007\002A)\021\021\005B\001\007yI|w\016\036 \n\005\rB\021A\002)sK\022,g-\003\002&M\t11\013\036:j]\036T!a\t\005\t\013!\"\002\031\001\017\002\007\025tG\rC\003+\001\021\0051&\001\003uKN$H#A\f") (bytes=
public class MyWalking
implements Walking
{
private String name;
private final String alias;
public void name_$eq(String x$1)
{
this.name = x$1;
}
public String alias()
{
return this.alias;
}
public void Walking$_setter_$alias_$eq(String x$1)
{
this.alias = x$1;
}
public MyWalking()
{
Walking.$init$(this);
}
public String name()
{
return this.name;
}
public void walk(String from, String end)
{
Predef..MODULE$.printf("walk from %s to %s.", Predef..MODULE$.genericWrapArray(new Object[] { from, end }));
}
public void test()
{
name_$eq("NEW NAME");
Predef..MODULE$.printf("new name is %s, alias is %s.", Predef..MODULE$.genericWrapArray(new Object[] { name(), alias() }));
}
}
可见
Predef
在scala中作用不凡
单例类-object
在scala中,没有静态修饰符,一般class
声明的类需要通过对象实例操作类中的方法,通过object
声明的类,就能通过类名直接调用类中的方法,这点与java语言中的static
修饰符有类似的地方。只有通过object
声明的类中的main
方法才能被当做程序的入口。object
声明的类,都会具有一个对应的隐式类(虚构类),隐式类的类名即为在该类名后面加$
,譬如:1
2
3
4
5
6
7
8
9
10
11
12object ObjectA {
var intVar: Int = 12
val intVal: Int = 23
def eat(food: String): Unit = {
println("eat " + food)
}
def main(args: Array[String]): Unit = {
eat("apple")
}
}
其反编译结果: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// 反编译object类 ObjectA.class
import scala.reflect.ScalaSignature;
"\006\001}:Q!\001\002\t\002\025\tqa\0242kK\016$\030IC\001\004\003\035aT-\0349usz\032\001\001\005\002\007\0175\t!AB\003\t\005!\005\021BA\004PE*,7\r^!\024\005\035Q\001CA\006\017\033\005a!\"A\007\002\013M\034\027\r\\1\n\005=a!AB!osJ+g\rC\003\022\017\021\005!#\001\004=S:LGO\020\013\002\013!9Ac\002a\001\n\003)\022AB5oiZ\013'/F\001\027!\tYq#\003\002\031\031\t\031\021J\034;\t\017i9\001\031!C\0017\005Q\021N\034;WCJ|F%Z9\025\005qy\002CA\006\036\023\tqBB\001\003V]&$\bb\002\021\032\003\003\005\rAF\001\004q\022\n\004B\002\022\bA\003&a#A\004j]R4\026M\035\021\t\017\021:!\031!C\001+\0051\021N\034;WC2DaAJ\004!\002\0231\022aB5oiZ\013G\016\t\005\006Q\035!\t!K\001\004K\006$HC\001\017+\021\025Ys\0051\001-\003\0211wn\0343\021\0055\"dB\001\0303!\tyC\"D\0011\025\t\tD!\001\004=e>|GOP\005\003g1\ta\001\025:fI\0264\027BA\0337\005\031\031FO]5oO*\0211\007\004\005\006q\035!\t!O\001\005[\006Lg\016\006\002\035u!)1h\016a\001y\005!\021M]4t!\rYQ\bL\005\003}1\021Q!\021:sCf\004") (bytes=
public final class ObjectA
{
public static void main(String[] paramArrayOfString)
{
ObjectA..MODULE$.main(paramArrayOfString);
}
public static void eat(String paramString)
{
ObjectA..MODULE$.eat(paramString);
}
public static int intVal()
{
return ObjectA..MODULE$.intVal();
}
public static void intVar_$eq(int paramInt)
{
ObjectA..MODULE$.intVar_$eq(paramInt);
}
public static int intVar()
{
return ObjectA..MODULE$.intVar();
}
}
// 其隐式Object类 Object$.class
import scala.Predef.;
public final class ObjectA$
{
public static MODULE$;
private int intVar;
private final int intVal;
public int intVar()
{
return this.intVar;
}
public void intVar_$eq(int x$1)
{
this.intVar = x$1;
}
public int intVal()
{
return this.intVal;
}
public void eat(String food)
{
Predef..MODULE$.println("eat " + food);
}
public void main(String[] args)
{
eat("apple");
}
private ObjectA$()
{
MODULE$ = this;this.intVar = 12;this.intVal = 23;
}
static
{
new ();
}
}
可以看出
object
声明的类是final
的,故继承object
是不能被继承的,其中声明的属性和方法都是static
的,也就没有必要实例化一个object
实例再去调用其中的方法,事实上object
也不能使用new
关键字去创建一个实例(trait
也一样),即object
声明的类是一个单例类。object
中的方法内容将在他的隐式类中体现并执行,它本身只是调用它隐式类中的同名方法。同时object
类不含有构造方法,它的”构造方法”也将在隐式类中体现,因为object
不提供构造方法,故object
也不能带有参数,如果object
的声明带有参数则会报错,譬如:
1
2
3 object ObjectA(name: String) {
... // 省略
}
其报错内容为
伴生类
用class
声明一个类,再使用object
声明一个与其名称一样的单例类,这两个类置于同一个.scala
文件中,则这个类就成为这个单例类的伴生类,这个单例类也就是该类的伴生对象(单例)。1
2
3
4
5
6
7
8
9
10
11
12
13class Man(name: String, age: Int) {
override def toString(): String = "name=" + name + ", age=" + age
def talk(words: String): Unit = {
printf("Man %s say: \"%s\" \n", name, words)
}
}
object Man {
def apply(name: String, age: Int): Man = new Man(name, age)
def apply(): Man = new Man("zero", 23)
}
其反编译内容: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// Man.class
import scala.Predef.;
import scala.reflect.ScalaSignature;
"\006\001y2A!\001\002\001\013\t\031Q*\0318\013\003\r\tq\001P3naRLhh\001\001\024\005\0011\001CA\004\013\033\005A!\"A\005\002\013M\034\027\r\\1\n\005-A!AB!osJ+g\r\003\005\016\001\t\005\t\025!\003\017\003\021q\027-\\3\021\005=1bB\001\t\025!\t\t\002\"D\001\023\025\t\031B!\001\004=e>|GOP\005\003+!\ta\001\025:fI\0264\027BA\f\031\005\031\031FO]5oO*\021Q\003\003\005\t5\001\021\t\021)A\0057\005\031\021mZ3\021\005\035a\022BA\017\t\005\rIe\016\036\005\006?\001!\t\001I\001\007y%t\027\016\036 \025\007\005\032C\005\005\002#\0015\t!\001C\003\016=\001\007a\002C\003\033=\001\0071\004C\003'\001\021\005s%\001\005u_N#(/\0338h)\005q\001\"B\025\001\t\003Q\023\001\002;bY.$\"a\013\030\021\005\035a\023BA\027\t\005\021)f.\033;\t\013=B\003\031\001\b\002\013]|'\017Z:\b\013E\022\001\022\001\032\002\0075\013g\016\005\002#g\031)\021A\001E\001iM\0211G\002\005\006?M\"\tA\016\013\002e!)\001h\rC\001s\005)\021\r\0359msR\031\021EO\036\t\01359\004\031\001\b\t\013i9\004\031A\016\t\013a\032D\021A\037\025\003\005\002") (bytes=
public class Man
{
private final String name;
private final int age;
public static Man apply()
{
return Man..MODULE$.apply();
}
public static Man apply(String paramString, int paramInt)
{
return Man..MODULE$.apply(paramString, paramInt);
}
public String toString()
{
return "name=" + this.name + ", age=" + this.age;
}
public void talk(String words)
{
Predef..MODULE$.printf("Man %s say: \"%s\" \n", Predef..MODULE$.genericWrapArray(new Object[] { this.name, words }));
}
public Man(String name, int age) {}
}
// Man$.class
public final class Man$
{
public static MODULE$;
static
{
new ();
}
public Man apply(String name, int age)
{
return new Man(name, age);
}
public Man apply()
{
return new Man("zero", 23);
}
private Man$()
{
MODULE$ = this;
}
}
在使用具有伴生对象的类时1
2
3
4
5
6
7
8
9
10
11
12
13object TestMan {
def main(args: Array[String]): Unit = {
val man01 = Man("第一个男人", 23)
val man02 = new Man("第二个男人", 22)
val man03 = Man.apply()
val man04 = Man.apply("第四个男人", 12)
println(man01) // name=第一个男人, age=23
println(man02) // name=第二个男人, age=22
println(man03) // name=zero, age=23
println(man04) // name=第四个男人, age=12
man03.talk("Hello!") // Man zero say: "Hello!"
}
}
类的伴生对象中的属性和方法都是
static
的,故使用伴生对象的方式可以拓展类的功能
scala中的枚举
在scala中,是没有enum
关键字的,那怎么去声明一个枚举类呢。通过object
的介绍可知,object
中的属性和方法都是static
的(其实还是final
的),同时,scala还提供Enumeration
这个abstract class
用来实现枚举类的声明,所以使用object
继承Enumeration
可以达到声明枚举类的功能。1
2
3
4
5
6
7
8
9
10
11
12
13
14object ColorEnum extends Enumeration {
val RED, GREEN = Value
val YELLOW = Value(12)
val BLACK = Value("黑色")
val BLUE = Value(99, "蓝色")
def main(args: Array[String]): Unit = {
println(ColorEnum.RED) // RED
println(ColorEnum.GREEN) // GREEN
println(ColorEnum.YELLOW) // YELLOW
println(ColorEnum.BLACK) // 黑色
println(ColorEnum.BLUE) // 蓝色
}
}
其反编译内容为: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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139// ColorEnum.class
import scala.Enumeration.Value;
import scala.Enumeration.ValueOrdering.;
import scala.Enumeration.ValueSet;
import scala.Enumeration.ValueSet.;
import scala.reflect.ScalaSignature;
"\006\001\t;Q!\001\002\t\002\025\t\021bQ8m_J,e.^7\013\003\r\tq\001P3naRLhh\001\001\021\005\0319Q\"\001\002\007\013!\021\001\022A\005\003\023\r{Gn\034:F]Vl7CA\004\013!\tYa\"D\001\r\025\005i\021!B:dC2\f\027BA\b\r\005-)e.^7fe\006$\030n\0348\t\013E9A\021\001\n\002\rqJg.\033;?)\005)\001b\002\013\b\005\004%\t!F\001\004%\026#U#\001\f\021\005]AR\"A\004\n\005eq!!\002,bYV,\007BB\016\bA\003%a#\001\003S\013\022\003\003bB\017\b\005\004%\t!F\001\006\017J+UI\024\005\007?\035\001\013\021\002\f\002\r\035\023V)\022(!\021\035\tsA1A\005\002U\ta!W#M\031>;\006BB\022\bA\003%a#A\004Z\0132cuj\026\021\t\017\025:!\031!C\001+\005)!\tT!D\027\"1qe\002Q\001\nY\taA\021'B\007.\003\003bB\025\b\005\004%\t!F\001\005\0052+V\t\003\004,\017\001\006IAF\001\006\0052+V\t\t\005\006[\035!\tAL\001\005[\006Lg\016\006\0020eA\0211\002M\005\003c1\021A!\0268ji\")1\007\fa\001i\005!\021M]4t!\rYQgN\005\003m1\021Q!\021:sCf\004\"\001O \017\005ej\004C\001\036\r\033\005Y$B\001\037\005\003\031a$o\\8u}%\021a\bD\001\007!J,G-\0324\n\005\001\013%AB*ue&twM\003\002?\031\001") (bytes=
public final class ColorEnum
{
public static void main(String[] paramArrayOfString)
{
ColorEnum..MODULE$.main(paramArrayOfString);
}
public static Enumeration.Value BLUE()
{
return ColorEnum..MODULE$.BLUE();
}
public static Enumeration.Value BLACK()
{
return ColorEnum..MODULE$.BLACK();
}
public static Enumeration.Value YELLOW()
{
return ColorEnum..MODULE$.YELLOW();
}
public static Enumeration.Value GREEN()
{
return ColorEnum..MODULE$.GREEN();
}
public static Enumeration.Value RED()
{
return ColorEnum..MODULE$.RED();
}
public static Enumeration.ValueSet. ValueSet()
{
return ColorEnum..MODULE$.ValueSet();
}
public static Enumeration.ValueOrdering. ValueOrdering()
{
return ColorEnum..MODULE$.ValueOrdering();
}
public static Enumeration.Value withName(String paramString)
{
return ColorEnum..MODULE$.withName(paramString);
}
public static Enumeration.Value apply(int paramInt)
{
return ColorEnum..MODULE$.apply(paramInt);
}
public static int maxId()
{
return ColorEnum..MODULE$.maxId();
}
public static Enumeration.ValueSet values()
{
return ColorEnum..MODULE$.values();
}
public static String toString()
{
return ColorEnum..MODULE$.toString();
}
}
// ColorEnum$.class
import scala.Enumeration;
import scala.Enumeration.Value;
import scala.Predef.;
public final class ColorEnum$
extends Enumeration
{
public static MODULE$;
private final Enumeration.Value RED;
private final Enumeration.Value GREEN;
private final Enumeration.Value YELLOW;
private final Enumeration.Value BLACK;
private final Enumeration.Value BLUE;
public Enumeration.Value RED()
{
return this.RED;
}
public Enumeration.Value GREEN()
{
return this.GREEN;
}
public Enumeration.Value YELLOW()
{
return this.YELLOW;
}
public Enumeration.Value BLACK()
{
return this.BLACK;
}
public Enumeration.Value BLUE()
{
return this.BLUE;
}
private ColorEnum$()
{
MODULE$ = this;
this.RED = Value();this.GREEN = Value();
this.YELLOW = Value(12);
this.BLACK = Value("黑色");
this.BLUE = Value(99, "蓝色");
}
public void main(String[] args)
{
Predef..MODULE$.println(RED());
Predef..MODULE$.println(GREEN());
Predef..MODULE$.println(YELLOW());
Predef..MODULE$.println(BLACK());
Predef..MODULE$.println(BLUE());
}
static
{
new ();
}
}