Javap
javap是JDK附带的一个工具,而不是JRE。它们之间还是有差别的。Javap反编译class文件,并且向你展示它里面放的是什么。使用起来很简单。
1
2
3
4
5
6
|
[local ~/projects/interop/target/scala_2. 8.1 /classes/com/twitter/interop]$ javap MyTrait
Compiled from "Scalaisms.scala"
public interface com.twitter.interop.MyTrait extends scala.ScalaObject{
public abstract java.lang.String traitName();
public abstract java.lang.String upperTraitName();
} |
如果你想了解底层的话,你可以查看对应的字节码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
[local ~/projects/interop/target/scala_2. 8.1 /classes/com/twitter/interop]$ javap -c MyTrait\$ class
Compiled from "Scalaisms.scala"
public abstract class com.twitter.interop.MyTrait$ class extends java.lang.Object{
public static java.lang.String upperTraitName(com.twitter.interop.MyTrait);
Code:
0 : aload_0
1 : invokeinterface # 12 , 1 ; //InterfaceMethod com/twitter/interop/MyTrait.traitName:()Ljava/lang/String;
6 : invokevirtual # 17 ; //Method java/lang/String.toUpperCase:()Ljava/lang/String;
9 : areturn
public static void $init$(com.twitter.interop.MyTrait);
Code:
0 : return
} |
如果你在Java平台上有什么问题,你可以通过javap来排查。
类
从Java的角度来使用Scala的_class_需要注意的四个要点如下:
- 类参数
- 类常量
- 类变量
- 异常
我们来创建一个简单的scala类来展示这几个要点
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
|
package com.twitter.interop
import java.io.IOException
import scala. throws
import scala.reflect.{BeanProperty, BooleanBeanProperty}
class SimpleClass(name: String, val acc: String, @BeanProperty var mutable: String) {
val foo = "foo"
var bar = "bar"
@BeanProperty
val fooBean = "foobean"
@BeanProperty
var barBean = "barbean"
@BooleanBeanProperty
var awesome = true
def dangerFoo() = {
throw new IOException( "SURPRISE!" )
}
@throws (classOf[IOException])
def dangerBar() = {
throw new IOException( "NO SURPRISE!" )
}
} |
类参数
- 默认情况下,类参数实际上就是Java里构造函数的参数。这就意味着你不能在这个class之外访问它们。
- 把类参数定义成一个val/var的方式和下面的代码相同
1
2
3
|
class SimpleClass(acc_: String) {
val acc = acc_
} |
下面就可以通过Java代码来访问它们了。
常量(Val)
- 常量(val)都会定义有对应的供Java代码访问的方法。你可以通过”foo()”方法来取得常量(val)“foo”的值。
变量(Var)
- 变量(var)会多定义一个_$eq方法。你可以这样调用来设置变量的值:
1
|
foo$_eq( "newfoo" );
|
BeanFactory
你可以通过@BeanProperty注解来标注val和var。这样就会生成类似于POJO的getter/setter方法。假如你想要访问isFoo变量,使用BooleanBeanProperty注解。那么难以理解的foo$eq就可以换成:
1
2
|
setFoo( "newfoo" );
getFoo(); |
异常
Scala里没有受检异常(checked exception),但是Java里有。这是一个语言层面上的问题,我们这里不进行讨论,但是在Java里你对异常进行捕获的时候你还是要注意的。dangerFoo和dangerBar的定义里对这进行了示范。在Java里,你不能这样做。
1
2
3
4
5
6
7
8
|
// exception erasure! // 异常擦除! try {
s.dangerFoo();
} catch (IOException e) {
// UGLY
// 非常丑陋
} |
Java编译器会因为s.dangerFoo不会抛出IOException而报错。我们可以通过捕获Throwable来绕过这个错误,但是这样做没多大用处。
不过,作为一个Scala用户,比较正式的方式是使用throws注解,就像我们之前在dangerBar上的一样。这个手段使得我们能够使用Java里的受检异常(checked exception)。
延伸阅读
支持Java互操作的注解的完整列表在http://www.scala-lang.org/node/106。
Trait
我们怎样可以得到一个接口和对应的实现呢?我们简单看看trait的定义
1
2
3
4
|
trait MyTrait { def traitName:String
def upperTraitName = traitName.toUpperCase
} |
这个trait有一个抽象的方法(traitName)和一个已实现的方法(upperTraitName)。对于这样的trait,Scala会生成什么样的代码呢?它会生成一个MyTrait接口,同时还会生成对应的实现类MyTrait$class。
MyTrait的实现和你猜想的差不多:
1
2
3
4
5
6
|
[local ~/projects/interop/target/scala_2. 8.1 /classes/com/twitter/interop]$ javap MyTrait
Compiled from "Scalaisms.scala"
public interface com.twitter.interop.MyTrait extends scala.ScalaObject{
public abstract java.lang.String traitName();
public abstract java.lang.String upperTraitName();
} |
不过MyTrait$class的实现更加有趣:
1
2
3
4
5
6
|
[local ~/projects/interop/target/scala_2. 8.1 /classes/com/twitter/interop]$ javap MyTrait\$ class
Compiled from "Scalaisms.scala"
public abstract class com.twitter.interop.MyTrait$ class extends java.lang.Object{
public static java.lang.String upperTraitName(com.twitter.interop.MyTrait);
public static void $init$(com.twitter.interop.MyTrait);
} |
MyTrait$class类只有一个静态的接受一个MyTrait实例作为参数的方法。这样给了我们在Java如何实现trait的一条线索。
首先要做的是:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package com.twitter.interop;
public class JTraitImpl implements MyTrait {
private String name = null ;
public JTraitImpl(String name) {
this .name = name;
}
public String traitName() {
return name;
}
} |
然后我们会得到下面的错误:
1
2
3
4
|
[info] Compiling main sources... [error] /Users/mmcbride/projects/interop/src/main/java/com/twitter/interop/JTraitImpl.java: 3 : com.twitter.interop.JTraitImpl is not abstract and does not override abstract method upperTraitName() in com.twitter.interop.MyTrait
[error] public class JTraitImpl implements MyTrait {
[error] ^ |
我们_可以_自己来实现他们。不过还有一种更加诡异的方式。
1
2
3
4
5
|
package com.twitter.interop;
public String upperTraitName() {
return MyTrait$ class .upperTraitName( this );
}
|
我们只需要把相应的方法调用代理到Scala的实现上。并且我们还可以根据实际需要进行重写。
对象
在Scala里,是用对象来实现静态方法和单例模式的。如果在Java里使用它们就会显得比较怪。在语法上没有什么比较优雅的方式来使用它们,但是在Scala 2.8里就没有那么麻烦了。
Scala对象会被编译成一个名称带有“$”后缀的类。我们来创建一个类以及对应的对象(Object)。我们来创建一个类以及对应的伴生对象(companion object)。
1
2
3
4
5
6
7
8
|
class TraitImpl(name: String) extends MyTrait {
def traitName = name
} object TraitImpl { def apply = new TraitImpl( "foo" )
def apply(name: String) = new TraitImpl(name)
} |
我们可以通过下面这种奇妙的方式在Java里访问它:
1
|
MyTrait foo = TraitImpl$.MODULE$.apply( "foo" );
|
现在你也许会问自己,这究竟是神马?这是一个很正常的反应。我们现在一起来看看TraintImpl$内部究竟是怎么实现的。
1
2
3
4
5
6
7
8
|
local ~/projects/interop/target/scala_2. 8.1 /classes/com/twitter/interop]$ javap TraitImpl\$
Compiled from "Scalaisms.scala"
public final class com.twitter.interop.TraitImpl$ extends java.lang.Object implements scala.ScalaObject{
public static final com.twitter.interop.TraitImpl$ MODULE$;
public static {};
public com.twitter.interop.TraitImpl apply();
public com.twitter.interop.TraitImpl apply(java.lang.String);
} |
其实它里面没有任何静态方法。相反,它还有一个静态成员叫做MODULE$。实际上方法的调用都是代理到这个成员变量上的。这种实现使得访问起来觉得比较恶心,但是如果你知道怎么使用MODULE$的话,其实还是很实用的。
转发方法(Forwarding Method)
在Scala 2.8里,处理Object会比较简单点。如果你有一个类以及对应的伴生对象(companion object),2.8 的编译器会在伴生对象里生成转发方法。如果使用2.8的编译器进行构建,那么你可以通过下面的方法来访问TraitImpl对象:
1
|
MyTrait foo = TraitImpl.apply( "foo" );
|
闭包函数
Scala最重要的一个特点就是把函数作为一等公民。我们来定义一个类,它里面包含一些接收函数作为参数的方法。
1
2
3
4
5
6
7
8
9
|
class ClosureClass {
def printResult[T](f: => T) = {
println(f)
}
def printResult[T](f: String => T) = {
println(f( "HI THERE" ))
}
} |
在Scala里我可以这样调用:
1
2
|
val cc = new ClosureClass
cc.printResult { "HI MOM" }
|
但是在Java里却没有这么简单,不过也没有想象的那么复杂。我们来看看ClosureClass最终到底编译成怎样:
1
2
3
4
5
6
7
|
[local ~/projects/interop/target/scala_2. 8.1 /classes/com/twitter/interop]$ javap ClosureClass
Compiled from "Scalaisms.scala"
public class com.twitter.interop.ClosureClass extends java.lang.Object implements scala.ScalaObject{
public void printResult(scala.Function0);
public void printResult(scala.Function1);
public com.twitter.interop.ClosureClass();
} |
这个看起来也不是很可怕。”f: => T” 转换成”Function0″,”f: String => T” 转换成 “Function1″。Scala定义了从Function0到Function22,一直支持到22个参数。这么多确实已经足够了。
现在我们只需要弄清楚,怎么在Java去实现这个功能。事实上,Scala提供了AbstractFunction0和AbstractFunction1,我们可以这样来传参:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@Test public void closureTest() {
ClosureClass c = new ClosureClass();
c.printResult( new AbstractFunction0() {
public String apply() {
return "foo" ;
}
});
c.printResult( new AbstractFunction1() {
public String apply(String arg) {
return arg + "foo" ;
}
});
} |
注意我们还可以使用泛型来参数化参数的类型。
相关推荐
在Java项目中使用Scala,通常被称为Java和Scala的混编。这种混编允许开发团队在已有的Java项目中逐渐引入Scala代码,以利用其优势,同时保持与现有Java代码的兼容性。在实际应用中,可能会在服务端逻辑或者特定组件...
JAVA+Scala语言开发基于机器学习的商品类目预测源码+文档说明.zip本资源中的源码都是经过本地编译过可运行的,评审分达到95分以上。资源项目的难度比较适中,内容都是经过助教老师审定过的能够满足学习、使用需求,...
基于java+scala+Python+spark实现的图书推荐系统的设计与实现+详细文档+全部资料(高分毕业设计).zip基于java+scala+Python+spark实现的图书推荐系统的设计与实现+详细文档+全部资料(高分毕业设计).zip ...
基于Java+Scala+Spark的图书推荐系统源码+详细文档+全部数据资料 高分项目.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的...
基于Java+Scala实现的深圳地铁大数据客流分析系统源代码+数据+详细文档,该项目主要分析深圳通刷卡数据,通过大数据技术角度来研究深圳地铁客运能力,探索深圳地铁优化服务的方向 以下是我的开发环境,仅作参考: ...
最新版本Spark2.1.1 java+scala官方API CHM(自己制作,有点小问题)
标题中的"一个基于Spring Boot的Spark开发手脚架(Java+Scala),开箱即用!模拟了1个WordCount.zip"表明这是一个使用Spring Boot框架构建的Spark应用程序,它结合了Java和Scala两种编程语言,旨在提供一个快速启动...
功能:实现google的PageRank算法,带完整的测试数据和结果,java、scala语言版本 ********************************************************* 版本: scala2.10.4 spark 1.6.1 Scala IDE Build id: 4.4.1-vfinal...
把厦门市的道路路网进行可视化展现(基于前端html页面或者java窗体);并能展现汽车移动。厦门市路网和各路段的速度可见附件文件(厦门...基于Akka框架(选择Java语言),完成以上消息发布、消息接收等模拟器编程。
Scala IDE 2.内容简介 Kafka是分布式的消息队列,作为云计算服务的基石,它广泛的应用在实时数据流方面,是实时数据处理的数据中枢,广泛应用在很多互联网企业,例如:linkedin,facebook,腾讯,百度,阿里等。实时...
在本压缩包中,我们关注的是Java、Hadoop、Scala和Spark这四个技术在Windows 10环境下的配置。这些工具广泛应用于大数据处理和分析领域,尤其是Spark在现代数据科学中扮演了重要角色。让我们逐一深入理解这些技术...
基于SpringBoot+Mybatis+Vue+Python+Scrapy+Spark+Scala协同过滤算法的新闻推荐系统的设计与实现+详细文档+全部资料(高分项目)数据爬虫使用Python+Scrapy框架,大数据推荐功能使用Spark+Scala实现协同过滤算法,...
它运行在Java虚拟机(JVM)上,可以无缝集成Java库,因此非常适合构建复杂、高性能的分布式系统。在大数据领域,Scala由于其强大的类型系统和表达能力,是Apache Spark的主要编程语言。 3. **Apache Spark**: ...
通常,.scala文件会被Notepad++默认识别为Java或者其他语言。我们可以在“菜单”->“首选项”->“新建文档/打开文件时的语言”中,将.scala扩展名与我们刚刚导入的Scala语言关联起来。这样,每次打开Scala文件时,...
这个过程涉及了Java语言替代品——Scala语言在Android开发中的应用。 Scala是一种静态类型的编程语言,它具有函数式编程和面向对象编程的特点,为开发者提供了更高级的抽象和语法糖,使得代码更加简洁和可读。将...
##Gradle+Scala+Java+SpringMVC Web应用解决方案 ###框架组成(Project Architecture) Gradle > > finished > 2016-10-23 Gretty Integration> Server Hot Deploy Scheme> > finished > 2016-11-05 Spring 4.25 ...
在本项目中,"springboot+scala+react"的组合为我们提供了一个现代Web应用程序的开发框架,结合了Spring Boot的强大后端能力、Scala的高效编程语法以及React的前端交互优势。下面将详细介绍这三个关键技术及其在项目...
本文主要讲述了如何在Eclipse中集成Maven和Scala,以便更好地进行Java开发。下面是相关知识点的总结: 一、JDK的下载和安装 * JDK是Java开发的基础环境,下载和安装JDK是开发的第一步。 * 在本文中,使用的JDK版本...
Scala运行在Java平台上(即Java虚拟机),这意味着它可以无缝地使用Java类库,同时也支持.NET平台。Scala的设计目的是为了提高生产力,通过减少代码量的同时保持代码的可读性和可维护性。 **2. 下载和安装Scala** ...