外文翻译面向Java开发人员的Scala指南类操作.docx
- 文档编号:23606967
- 上传时间:2023-05-18
- 格式:DOCX
- 页数:17
- 大小:26.39KB
外文翻译面向Java开发人员的Scala指南类操作.docx
《外文翻译面向Java开发人员的Scala指南类操作.docx》由会员分享,可在线阅读,更多相关《外文翻译面向Java开发人员的Scala指南类操作.docx(17页珍藏版)》请在冰豆网上搜索。
外文翻译面向Java开发人员的Scala指南类操作
面向Java开发人员的Scala指南:
类操作
Java开发人员可以将对象作为理解Scala的出发点。
本文是面向Java开发人员的Scala指南系列的第二期,作者TedNeward遵循对一种语言进行评价的基本前提:
一种语言的威力可以直接通过它集成新功能的能力衡量,在本文中就是指对复数的支持。
跟随本文,您将了解在Scala中与类的定义和使用有关的一些有趣特性。
在上一期文章中,您只是稍微了解了一些Scala语法,这些是运行Scala程序和了解其简单特性的最基本要求。
通过上一篇文章中的HelloWorld和Timer示例程序,您了解了Scala的Application类、方法定义和匿名函数的语法,还稍微了解Array[]和一些类型推断方面的知识。
Scala还提供了很多其他特性,本文将研究Scala编程中的一些较复杂方面。
Scala的函数编程特性非常引人注目,但这并非Java开发人员应该对这门语言感兴趣的惟一原因。
实际上,Scala融合了函数概念和面向对象概念。
为了让Java和Scala程序员感到得心应手,可以了解一下Scala的对象特性,看看它们是如何在语言方面与Java对应的。
记住,其中的一些特性并不是直接对应,或者说,在某些情况下,“对应”更像是一种类比,而不是直接的对应。
不过,遇到重要区别时,我会指出来。
1.Scala和Java一样使用类
我们不对Scala支持的类特性作冗长而抽象的讨论,而是着眼于一个类的定义,这个类可用于为Scala平台引入对有理数的支持(主要借鉴自“ScalaByExample”,参见参考资料):
清单1.rational.scala
classRational(n:
Int,d:
Int)
{
privatedefgcd(x:
Int,y:
Int):
Int=
{
if(x==0)y
elseif(x<0)gcd(-x,y)
elseif(y<0)-gcd(x,-y)
elsegcd(y%x,x)
}
privatevalg=gcd(n,d)
valnumer:
Int=n/g
valdenom:
Int=d/g
def+(that:
Rational)=
newRational(numer*that.denom+that.numer*denom,denom*that.denom)
def-(that:
Rational)=
newRational(numer*that.denom-that.numer*denom,denom*that.denom)
def*(that:
Rational)=
newRational(numer*that.numer,denom*that.denom)
def/(that:
Rational)=
newRational(numer*that.denom,denom*that.numer)
overridedeftoString()=
"Rational:
["+numer+"/"+denom+"]"
}
从词汇上看,清单1的整体结构与Java代码类似,但是,这里显然还有一些新的元素。
在详细讨论这个定义之前,先看一段使用这个新Rational类的代码:
清单2.RunRational
classRational(n:
Int,d:
Int)
{
//...asbefore
}
objectRunRationalextendsApplication
{
valr1=newRational(1,3)
valr2=newRational(2,5)
valr3=r1-r2
valr4=r1+r2
Console.println("r1="+r1)
Console.println("r2="+r2)
Console.println("r3=r1-r2="+r3)
Console.println("r4=r1+r2="+r4)
}
清单2中的内容平淡无奇:
先创建两个有理数,然后再创建两个Rational,作为前面两个有理数的和与差,最后将这几个数回传到控制台上(注意,Console.println()来自Scala核心库,位于scala.*中,它被隐式地导入每个Scala程序中,就像Java编程中的java.lang一样)。
用多少种方法构造类?
现在,回顾一下Rational类定义中的第一行:
清单3.Scala的默认构造函数
classRational(n:
Int,d:
Int)
{
//...
您也许会认为清单3中使用了某种类似于泛型的语法,这其实是Rational类的默认的、首选的构造函数:
n和d是构造函数的参数。
Scala优先使用单个构造函数,这具有一定的意义——大多数类只有一个构造函数,或者通过一个构造函数将一组构造函数“链接”起来。
如果需要,可以在一个Rational上定义更多的构造函数,例如:
清单4.构造函数链
classRational(n:
Int,d:
Int)
{
defthis(d:
Int)={this(0,d)}
注意,Scala的构造函数链通过调用首选构造函数(Int,Int版本)实现Java构造函数链的功能。
2.实现细节
在处理有理数时,采取一点数值技巧将会有所帮助:
也就是说,找到公分母,使某些操作变得更容易。
如果要将1/2与2/4相加,那Rational类应该足够聪明,能够认识到2/4和1/2是相等的,并在将这两个数相加之前进行相应的转换。
嵌套的私有gcd()函数和Rational类中的g值可以实现这样的功能。
在Scala中调用构造函数时,将对整个类进行计算,这意味着将g初始化为n和d的最大公分母,然后用它依次设置n和d。
回顾一下清单1就会发现,我创建了一个覆盖的toString方法来返回Rational的值,在RunRational驱动程序代码中使用toString时,这样做非常有用。
然而,请注意toString的语法:
定义前面的override关键字是必需的,这样Scala才能确认基类中存在相应的定义。
这有助于预防因意外的输入错误导致难于觉察的bug(Java5中创建@Override注释的动机也在于此)。
还应注意,这里没有指定返回类型——从方法体的定义很容易看出——返回值没有用return关键字显式地标注,而在Java中则必须这样做。
相反,函数中的最后一个值将被隐式地当作返回值(但是,如果您更喜欢Java语法,也可以使用return关键字)。
3.一些重要值
接下来分别是numer和denom的定义。
这里涉及的语法可能让Java程序员认为numer和denom是公共的Int字段,它们分别被初始化为n-over-g和d-over-g;但这种想法是不对的。
在形式上,Scala调用无参数的numer和denom方法,这种方法用于创建快捷的语法以定义accessor。
Rational类仍然有3个私有字段:
n、d和g,但是,其中的n和d被默认定义为私有访问,而g则被显式地定义为私有访问,它们对于外部都是隐藏的。
此时,Java程序员可能会问:
“n和d各自的‘setter’在哪里?
”Scala中不存在这样的setter。
Scala的一个强大之处就在于,它鼓励开发人员以默认方式创建不可改变的对象。
但是,也可使用语法创建修改Rational内部结构的方法,但是这样做会破坏该类固有的线程安全性。
因此,至少对于这个例子而言,我将保持Rational不变。
当然还有一个问题,如何操纵Rational呢?
与java.lang.String一样,不能直接修改现有的Rational的值,所以惟一的办法是根据现有类的值创建一个新的Rational,或者从头创建。
这涉及到4个名称比较古怪的方法:
+、-、*和/。
与其外表相反,这并非操作符重载。
4.操作符
记住,在Scala中一切都是对象。
在上一篇文章中,您看到了函数本身也是对象这一原则的应用,这使Scala程序员可以将函数赋予变量,将函数作为对象参数传递等等。
另一个同样重要的原则是,一切都是函数;也就是说,在此处,命名为add的函数与命名为+的函数没有区别。
在Scala中,所有操作符都是类的函数。
只不过它们的名称比较古怪罢了。
在Rational类中,为有理数定义了4种操作。
它们是规范的数学操作:
加、减、乘、除。
每种操作以它的数学符号命名:
+、-、*和/。
但是请注意,这些操作符每次操作时都构造一个新的Rational对象。
同样,这与java.lang.String非常相似,这是默认的实现,因为这样可以产生线程安全的代码(如果线程没有修改共享状态——默认情况下,跨线程共享的对象的内部状态也属于共享状态——则不会影响对那个状态的并发访问)。
5.有什么变化
首先,您已经看到,函数可以作为对象进行操纵和存储。
这使函数具有强大的可重用性,本系列第一篇文章对此作了探讨。
第二个影响是,Scala语言设计者提供的操作符与Scala程序员认为应该提供的操作符之间没有特别的差异。
例如,假设提供一个“求倒数”操作符,这个操作符会将分子和分母调换,返回一个新的Rational(即对于Rational(2,5)将返回Rational(5,2))。
如果您认为~符号最适合表示这个概念,那么可以使用此符号作为名称定义一个新方法,该方法将和Java代码中任何其他操作符一样,如清单5所示:
清单5.求倒数
valr6=~r1
Console.println(r6)//shouldprint[3/1],sincer1=[1/3]
在Scala中定义这种一元操作符”需要一点技巧,但这只是语法上的问题而已:
清单6.如何求倒数
classRational(n:
Int,d:
Int)
{
//...asbefore...
defunary_~:
Rational=
newRational(denom,numer)
}
当然,需要注意的地方是,必须在名称~之前加上前缀“unary_”,告诉Scala编译器它属于一元操作符。
因此,该语法将颠覆大多数对象语言中常见的传统reference-then-method语法。
这条规则与“一切都是对象”规则结合起来,可以实现功能强大(但很简单)的代码:
清单7.求和
1+2+3//sameas1.+(2.+(3))
r1+r2+r3//sameasr1.+(r2.+(r3))
当然,对于简单的整数加法,Scala编译器也会“得到正确的结果”,它们在语法上是完全一样的。
这意味着您可以开发与Scala语言“内置”的类型完全相同的类型。
Scala编译器甚至会尝试推断具有某种预定含义的“操作符”的其他含义,例如+=操作符。
注意,虽然Rational类并没有显式地定义+=,下面的代码仍然会正常运行:
清单8.Scala推断
varr5=newRational(3,4)
r5+=r1
Console.println(r5)
打印结果时,r5的值为[13/12],结果是正确的。
6.Scala内幕
记住,Scala将被编译为Java字节码,这意味着它在JVM上运行。
如果您需要证据,那么只需注意编译器生成以0xCAFEBABE开头的.class文件,就像javac一样。
另外请注意,如果启动JDK自带的Java字节码反编译器(javap),并将它指向生成的Rational类,将会出现什么情况,如清单9所示:
清单9.从rational.scala编译的类
C:
\Projects\scala-classes\code>javap-private-classpathclassesRational
Compiledfrom"rational.scala"
publicclassRationalextendsjava.lang.Objectimplementsscala.ScalaObject{
privateintdenom;
privateintnumer;
privateintg;
publicRational(int,int);
publicRationalunary_$tilde();
publicjava.lang.StringtoString();
publicRational$div(Rational);
publicRational$times(Rational);
publicRational$minus(Rational);
publicRational$plus(Rational);
publicintdenom();
publicintnumer();
privateintg();
privateintgcd(int,int);
publicRational(int);
publicint$tag();
}
C:
\Projects\scala-classes\code>
Scala类中定义的“操作符”被转换成传统Java编程中的方法调用,不过它们仍使用看上去有些古怪的名称。
类中定义了两个构造函数:
一个构造函数带有一个int参数,另一个带有两个int参数。
您可能会注意到,大写的Int类型与java.lang.Integer有点相似,Scala编译器非常聪明,会在类定义中将它们转换成常规的Java原语int。
7.结束语
Scala将函数概念与简洁性相融合,同时又未失去对象的丰富特性。
从本系列中您可能已经看到,Scala还修正了Java语言中的一些语法问题(后见之明)。
本文是面向Java开发人员的Scala指南系列中的第二篇文章,本文主要讨论Scala的对象特性,使您可以开始使用Scala,而不必深入探究函数方面。
应用目前学到的知识,您现在可以使Scala减轻编程负担。
而且,可以使用Scala生成其他编程环境(例如Spring或Hibernate)所需的POJO。
原文出处:
thinkinjava
ThebusyJavadeveloper'sguidetoScala:
Classaction
ItmakessenseforJava™developerstouseobjectsasafirstpointofreferenceforunderstandingScala.InthissecondinstallmentofThebusyJavadeveloper'sguidetoScalaseries,TedNewardfollowsabasicpremiseoflanguagemeasurement:
thatthepowerofalanguagecanbemeasuredindirectrelationtoitsabilitytointegratenewfacilities--inthiscase,supportforcomplexnumbers.Alongthewayyou'llseesomeinterestingtidbitsrelatedtoclassdefinitionsandusageinScala.Inlastmonth'sarticle,yousawjustatouchofScala'ssyntax,thebareminimumnecessarytorunaScalaprogramandobservesomeofitssimplerfeatures.TheHelloWorldandTimerexamplesfromthatarticleletyouseeScala'sApplicationclass,itssyntaxformethoddefinitionsandanonymousfunctions,justaglimpseofanArray,andabitontype-inferencing.Scalahasagreatdealmoretooffer,sothisarticleinvestigatestheintricaciesofScalacoding.
Scala'sfunctionalprogrammingfeaturesarecompelling,butthey'renottheonlyreasonJavadevelopersshouldbeinterestedinthelanguage.Infact,Scalablendsfunctionalconceptsandobjectorientation.InordertolettheJava-cum-Scalaprogrammerfeelmoreathome,itmakessensetolookatScala'sobjectfeaturesandseehowtheymapovertoJavalinguistically.Bearinmindthatthereisn'tadirectmappingforsomeofthesefeatures,orinsomecases,the"mapping"ismoreofananalogthanadirectparallel.Butwherethedistinctionisimportant,I'llpointitout.
1.Scalahasclass(es),too
RatherthanembarkonalengthyandabstractdiscussionoftheclassfeaturesthatScalasupports,let'slookatadefinitionforaclassthatmightbeusedtobringrationalnumbersupporttotheScalaplatform(largelyswipedfrom"ScalaByExample"--seeResources):
Listing1.rational.scala
classRational(n:
Int,d:
Int)
{
privatedefgcd(x:
Int,y:
Int):
Int=
{
if(x==0)y
elseif(x<0)gcd(-x,y)
elseif(y<0)-gcd(x,-y)
elsegcd(y%x,x)
}
privatevalg=gcd(n,d)
valnumer:
Int=n/g
valdenom:
Int=d/g
def+(that:
Rational)=
newRational(numer*that.denom+that.numer*denom,denom*that.denom)
def-(that:
Rational)=
newRational(numer*that.denom-that.numer*denom,denom*that.denom)
def*(that:
Rational)=
newRational(numer*that.numer,denom*that.denom)
def/(that:
Rational)=
newRational(numer*that.denom,denom*that.numer)
overridedeftoString()=
"Rational:
["+numer+"/"+denom+"]"
}
WhiletheoverallstructureofListing1islexicallysimilartowhatyou'veseeninJavacodeoverthelastdecade,somenewelementsclearlyareatworkhere.Beforepickingthisdefinitionapart,takealookatthecodetoexercisethenewRationalclass:
Listing2.RunRational
classRational(n:
Int,d:
Int)
{
//...asbefore
}
objectRunRationalextendsApplication
{
valr1=newRational(1,3)
valr2=newRational(2,5)
valr3=r1-r2
valr4=r1+r2
Console.println("r1="+r1)
Console.println("r2="+r2)
Console.println("r3=r1-r2="+r3)
Console.println("r4=r1+r2="+r4)
}
WhatyouseeinListing2isn'tterriblyexciting:
Icreateacoupleofrationalnumbers,createtwomoreRationalsastheadditionandsubtractionofthefirsttwo,andechoeverythingtotheconsole.(NotethatConsole.println()comesfromtheScalacorelibrary,livinginscala.*,andisimplicitlyimportedintoeveryScalaprogram,justasjava.langisinJavaprogramming.)
HowmanywaysshallIconstructthee?
NowlookagainatthefirstlineintheRationalclassdefinition:
Listing3.Scala'sde
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 外文 翻译 面向 Java 开发人员 Scala 指南 操作