Scala的面向对象编程风格带有一些语法糖和一些技巧。
为了更好地了解Scala的工作原理,我们将研究一些Scala示例和相应的字节代码(实际上是反编译类文件所产生的Java代码)。
Examples Empty Class 最简单的例子,一个空的类。这里只有一个带有无参数构造函数的类,这不足为奇。顺便说一句,如本例所示,Scala中的默认可见性修饰符是public
//Scala class Empty
//Java public class Empty {}
有参数但没有字段的类 带有参数的构造函数的类:它导致带有all-args构造函数的类。 任何方法之外的类的主体都被视为构造函数定义的一部分。
//Scala class Fraction(n: Int, d: Int) { System.out.println("numerator:" + n + ", denominator:" + d) }
//Java public Fraction(final int n, final int d) { System.out.println("numerator:" + n + ", denominator:" + d); }
具有参数提升为字段的类 当构造函数的参数由构造函数以外的类的成员使用时,这些参数将提升为字段,以便可以对其进行访问。
//Scala class FractionString(n: Int, d: Int){ override def toString: String = n + "/" + d }
//Java public class FractionString { private final int n; private final int d; public String toString() { return this.n + "/" + this.d; } public FractionString(final int n, final int d) { this.n = n; this.d = d; } }
值得注意的是,生成的字段的可见性是对象专用的(private [this]),这意味着它们不能被同一类的其他对象访问。例如,此示例将无法编译:
//Scala class FractionEqual(n: Int, d: Int){ override def equals(other: Any): Boolean = other match { case that: FractionEqual => n == that.n && d == that.d case _ => false } } Error:(32, 43) value n is not a member of FractionEqual case that: FractionEqual => n == that.n && d == that.d
有趣的是,修饰符private [this]在JVM中没有意义,因此被编译为private。
带参数字段的类 关键字val可以用作同时定义参数和名称相同的字段的简写形式。该字段伴随有一个名为字段的吸气剂。
//Scala class FractionVal(val n: Int, val d: Int)
//Java public class FractionVal { private final int n; private final int d; public int n() { return this.n; } public int d() { return this.d; } public FractionVal(final int n, final int d) { this.n = n; this.d = d; } }
但是,所有设计都是为了制造一种幻想,即没有方法。在这种情况下,将getter定义为无参数方法,因此客户端将忽略他们正在调用val还是def。 这是Scala支持统一访问原则的方式:
客户端代码不应受到将属性实现为字段或方法的决定的影响。
不幸的是,这在Java版本中无法理解,因为它显示了用括号定义的方法,一个空括号的方法,因为在JVM领域中不存在无参数方法。
但是,以下示例说明了它在Scala中的工作方式:
scala> class FractionVal(val n: Int, val d: Int) defined class FractionVal scala> val f = new FractionVal(1,2 f: FractionVal = FractionVal@2102eb7a scala> f.n res17: Int = 1 scala> f.d res18: Int = 2 scala> f.n() <console>:13: error: Int does not take parameters f.n()
现在,将有可能实现的方法等于S作为字段都可以通过相应的公共访问干将。
带有var的参数字段 也可以使用关键字var定义参数字段。在这种情况下,还将生成一个名为field_ =的设置器。
//Scala class FractionVar(var n: Int, var d: Int)
//Java public class FractionVar { private int n; private int d; public int n() { return this.n; } public void n_$eq(final int x$1) { this.n = x$1; } public int d() { return this.d; } public void d_$eq(final int x$1) { this.d = x$1; } public FractionVar(final int n, final int d) { this.n = n; this.d = d; super(); } }
与前面的示例类似,将setter field_ =解释为赋值运算符,以产生没有方法的错觉。尽管在这种情况下,也可以直接调用设置器:
scala> class FractionVar(var n: Int, var d: Int) defined class FractionVar scala> val f = new FractionVar(1,2) f: FractionVar = FractionVar@1ecdfe1e scala> f.n res20: Int = 1 scala> f.n = 9 f.n: Int = 9 scala> f.n res21: Int = 9 scala> f.n_=(10) scala> f.n res24: Int = 10
生成的getter / setter 的可见性与相应的val / var的可见性相同
带有自定义Getter / Setter的类 按照Java的传统,我们还可以创建自己的getter / setter方法。但是,对变量的访问仍然是通过合成的getter / setter完成的。
//Scala class FractionVar(var n: Int, var d: Int){ def setN(n: Int) = this.n = n def getN() = n }
//Java public class FractionVar { private int n; private int d; public int n() { return this.n; } public void n_$eq(final int x$1) { this.n = x$1; } public int d() { return this.d; } public void d_$eq(final int x$1) { this.d = x$1; } public void setN(final int n) { this.n_$eq(n); } public int getN() { return this.n(); } public FractionVar(final int n, final int d) { this.n = n; this.d = d; super(); } }
这是有关如何使用新方法的示例。注意如何在带或不带括号的情况下调用getN
scala> :paste // Entering paste mode (ctrl-D to finish) class FractionVar(var n: Int, var d: Int){ def setN(n: Int) = this.n = n def getN() = n } // Exiting paste mode, now interpreting. defined class FractionVar scala> val f = new FractionVar(1,2) f: FractionVar = FractionVar@125490ea scala> f.getN() res26: Int = 1 scala> f.getN res27: Int = 1 scala> f.setN(9) scala> f.getN res29: Int = 9
Object 对象被编译为两个类:
名称后缀为$并包含实际功能的单例 具有静态转发器的类,以访问单例功能。
//Scala object FractionObject { def fraction(n: Int, d: Int) = n + "/" + d }
//Java public final class FractionObject$ { public static FractionObject$ MODULE$; static { new FractionObject$(); } public String fraction(final int n, final int d) { return n + "/" + d; } private FractionObject$() { MODULE$ = this; } } public final class FractionObject { public static String fraction(int var0, int var1) { return FractionObject$.MODULE$.fraction(var0, var1); } }
Companion Object Scala中的伴随对象是与类在同一文件中声明的对象,并且与该类具有相同的名称。与前面的情况类似,创建了一个单例和一个转发器。 唯一的区别是,现在单例实现了AbstractFunction(具有相应的-arity)和Serializable。
//Scala class FractionVal(val n: Int, val d: Int) object FractionVal
//Java public final class FractionVal$ extends AbstractFunction2 implements Serializable { public static FractionVal$ MODULE$; static { new FractionVal$(); } public final String toString() { return "FractionVal"; } public FractionVal apply(final int n, final int d) { return new FractionVal(n, d); } public Option unapply(final FractionVal x$0) { return (Option)(x$0 == null ? .MODULE$ : new Some(new sp(x$0.n(), x$0.d()))); } private Object readResolve() { return MODULE$; } // $FF: synthetic method // $FF: bridge method public Object apply(final Object v1, final Object v2) { return this.apply(BoxesRunTime.unboxToInt(v1), BoxesRunTime.unboxToInt(v2)); } private FractionVal$() { MODULE$ = this; } } public class FractionVal { private final int n; private final int d; public int n() { return this.n; } public int d() { return this.d; } public FractionVal(final int n, final int d) { this.n = n; this.d = d; } }
有趣的是,由于FractionVal没有任何对FractionVal $的引用,因此在Scala中无法使用单例实现的功能。 例如,方法apply不可用,而toString使用Object.toString给定的实现,而不是FractionVal $ .toString
scala> :paste // Entering paste mode (ctrl-D to finish) class FractionVal(val n: Int, val d: Int) object FractionVal // Exiting paste mode, now interpreting. defined class FractionVal defined object FractionVal scala> FractionVal(1,2) <console>:13: error: FractionVal.type does not take parameters FractionVal(1,2) ^ scala> new FractionVal(1,2) res5: FractionVal = FractionVal@7f2c995b
Case Class 案例类是具有大量功能的常规类。
这是结果类的结构:
//Scala case class FractionVal(n: Int, d: Int)
//Java import scala.Option; import scala.Serializable; import scala.Some; import scala.None.; import scala.Tuple2.mcII.sp; import scala.runtime.AbstractFunction2; import scala.runtime.BoxesRunTime; public final class FractionVal$ extends AbstractFunction2 implements Serializable { public static FractionVal$ MODULE$; static { new FractionVal$(); } public final String toString() { return "FractionVal"; } public FractionVal apply(final int n, final int d) { return new FractionVal(n, d); } public Option unapply(final FractionVal x$0) { return (Option)(x$0 == null ? .MODULE$ : new Some(new sp(x$0.n(), x$0.d()))); } private Object readResolve() { return MODULE$; } // $FF: synthetic method // $FF: bridge method public Object apply(final Object v1, final Object v2) { return this.apply(BoxesRunTime.unboxToInt(v1), BoxesRunTime.unboxToInt(v2)); } private FractionVal$() { MODULE$ = this; } } import scala.Function1; import scala.Option; import scala.Product; import scala.Serializable; import scala.collection.Iterator; import scala.reflect.ScalaSignature; import scala.runtime.BoxesRunTime; import scala.runtime.Statics; import scala.runtime.ScalaRunTime.; public class FractionVal implements Product, Serializable { private final int n; private final int d; public static Option unapply(final FractionVal x$0) { return FractionVal$.MODULE$.unapply(var0); } public static FractionVal apply(final int n, final int d) { return FractionVal$.MODULE$.apply(var0, var1); } public static Function1 tupled() { return FractionVal$.MODULE$.tupled(); } public static Function1 curried() { return FractionVal$.MODULE$.curried(); } public int n() { return this.n; } public int d() { return this.d; } public FractionVal copy(final int n, final int d) { return new FractionVal(n, d); } public int copy$default$1() { return this.n(); } public int copy$default$2() { return this.d(); } public String productPrefix() { return "FractionVal"; } public int productArity() { return 2; } public Object productElement(final int x$1) { Integer var10000; switch(x$1) { case 0: var10000 = BoxesRunTime.boxToInteger(this.n()); break; case 1: var10000 = BoxesRunTime.boxToInteger(this.d()); break; default: throw new IndexOutOfBoundsException(BoxesRunTime.boxToInteger(x$1).toString()); } return var10000; } public Iterator productIterator() { return .MODULE$.typedProductIterator(this); } public boolean canEqual(final Object x$1) { return x$1 instanceof FractionVal; } public int hashCode() { int var1 = -889275714; var1 = Statics.mix(var1, this.n()); var1 = Statics.mix(var1, this.d()); return Statics.finalizeHash(var1, 2); } public String toString() { return .MODULE$._toString(this); } public boolean equals(final Object x$1) { boolean var10000; if (this != x$1) { label51: { boolean var2; if (x$1 instanceof FractionVal) { var2 = true; } else { var2 = false; } if (var2) { FractionVal var4 = (FractionVal)x$1; if (this.n() == var4.n() && this.d() == var4.d() && var4.canEqual(this)) { break label51; } } var10000 = false; return var10000; } } var10000 = true; return var10000; } public FractionVal(final int n, final int d) { this.n = n; this.d = d; Product.$init$(this); } }
Case Object 也可以定义案例对象。再次,创建一个单例和一个转发器。最值得注意的是,单例实现Serializable和Product。
//Scala ` case object FractionObject
//Java import scala.collection.Iterator; public final class FractionObject { public static String toString() { return FractionObject$.MODULE$.toString(); } public static int hashCode() { return FractionObject$.MODULE$.hashCode(); } public static boolean canEqual(final Object x$1) { return FractionObject$.MODULE$.canEqual(var0); } public static Iterator productIterator() { return FractionObject$.MODULE$.productIterator(); } public static Object productElement(final int x$1) { return FractionObject$.MODULE$.productElement(var0); } public static int productArity() { return FractionObject$.MODULE$.productArity(); } public static String productPrefix() { return FractionObject$.MODULE$.productPrefix(); } } import scala.Product; import scala.Serializable; import scala.collection.Iterator; import scala.runtime.BoxesRunTime; import scala.runtime.ScalaRunTime.; public final class FractionObject$ implements Product, Serializable { public static FractionObject$ MODULE$; static { new FractionObject$(); } public String productPrefix() { return "FractionObject"; } public int productArity() { return 0; } public Object productElement(final int x$1) { throw new IndexOutOfBoundsException(BoxesRunTime.boxToInteger(x$1).toString()); } public Iterator productIterator() { return .MODULE$.typedProductIterator(this); } public boolean canEqual(final Object x$1) { return x$1 instanceof FractionObject$; } public int hashCode() { return 1259148289; } public String toString() { return "FractionObject"; } private Object readResolve() { return MODULE$; } private FractionObject$() { MODULE$ = this; Product.$init$(this); } }
Trait Trait被编译为接口
//Scala trait FractionTrait{ val n: Int val d: Int }
//Java public interface FractionTrait { int n(); int d(); }
Abstract Class 具体类的规则也适用于抽象类
//Scala abstract class AbstractFraction(val n: Int, val d: Int)
//Java public abstract class AbstractFraction { private final int n; private final int d; public int n() { return this.n; } public int d() { return this.d; } public AbstractFraction(final int n, final int d) { this.n = n; this.d = d; } }
Package Object 包对象被视为对象。创建两类:一单叫包$和代理类称为包
//Scala package object mypackage { def greet() = "hello" }
//Java package mypackage; public final class package { public static String greet() { return package$.MODULE$.greet(); } } public final class package$ { public static package$ MODULE$; static { new package$(); } public String greet() { return "hello"; } private package$() { MODULE$ = this; } }
原文链接:http://codingdict.com