专栏名称: ImportNew
伯乐在线旗下账号,专注Java技术分享,包括Java基础技术、进阶技能、架构设计和Java技术领域动态等。
目录
相关文章推荐
51好读  ›  专栏  ›  ImportNew

Scala 与 Java 的交互操作

ImportNew  · 公众号  · Java  · 2017-01-06 20:18

正文

(点击 上方公众号 ,可快速关注)


英文:Scala School

译文:朱伟杰

如需转载,发送「转载」二字查看说明


这个章节主要讲解Scala和Java进行互操作。


  • Javap

  • 异常

  • Trait

  • 对象

  • 闭包函数(closures functions)


Javap


javap是JDK附带的一个工具,而不是JRE。它们之间还是有差别的。Javap反编译class文件,并且向你展示它里面放的是什么。使用起来很简单。


[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();

}


如果你想了解底层的话,你可以查看对应的字节码


[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类来展示这几个要点


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的方式和下面的代码相同


class SimpleClass(acc_: String) {

val acc = acc_

}


下面就可以通过Java代码来访问它们了。


常量(Val)


  • 常量(val)都会定义有对应的供Java代码访问的方法。你可以通过”foo()”方法来取得常量(val)“foo”的值。


变量(Var)


  • 变量(var)会多定义一个_$eq方法。你可以这样调用来设置变量的值:


foo$_eq("newfoo");


BeanFactory


你可以通过@BeanProperty注解来标注val和var。这样就会生成类似于POJO的getter/setter方法。假如你想要访问isFoo变量,使用BooleanBeanProperty注解。那么难以理解的foo$eq就可以换成:


setFoo("newfoo");

getFoo();


异常


Scala里没有受检异常(checked exception),但是Java里有。这是一个语言层面上的问题,我们这里不进行讨论,但是在Java里你对异常进行捕获的时候你还是要注意的。dangerFoo和dangerBar的定义里对这进行了示范。在Java里,你不能这样做。


// 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的定义


trait MyTrait {

def traitName:String

def upperTraitName = traitName.toUpperCase

}


这个trait有一个抽象的方法(traitName)和一个已实现的方法(upperTraitName)。对于这样的trait,Scala会生成什么样的代码呢?它会生成一个MyTrait接口,同时还会生成对应的实现类MyTrait$class。


MyTrait的实现和你猜想的差不多:


[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{







请到「今天看啥」查看全文