Scala和Java互操作

2017/11/22 Scala

Scala和Java互操作

Java 对类型、方法、字段和变量名的规定比 Scala 更加严格。所以,几乎所有情况下,你都可以在 Scala 代码中使用 Java 名称,创建 Java 类型的新 实例,调用 Java 方法,使用 Java 变量与实例字段。 唯一的例外是,Java 的名字实际上是 Scala 的关键字的情况。我们需要使用反引号进行“转义”。

Java泛型和Scala泛型

在Java中使用Scala的参数化类型,可以如下方式运行:

//  混入了程序的scala特征,会使用ScalaTest来运行
public class SMapTest org.scala.test.Junit.JUnitSuit{
    static class Name{
        public String firstName;
        public String lastName;
    }

    public Name(String firstName,lastName){
        this.firstName=firstName;
        this.lastName=lastName;
    }

    LinkedHashMap<Integer,Name> map;

    @Before
    public void setup(){
        map=new LinkedHashMap<Integer,Name>();
        map.update(1,new Name("Dean","Wampler"));
    }

    @Test
    public void usingMapGetWithOptionName(){
        assertEquals(1,map.size());
        Option<Name> n1=map.get(1); //这种写法完成后不需要自己转换类型
        assertTure(n1.isDefined());
        assertEquals("Dean",n1.get().firstName);
    }

    @Test
    public void usingMapGetWithOptionExistential(){
        assertEquals(1, map.size());
        Option<?> n1 = map.get(1); 
        Option<?> assertTrue(n1.isDefined());
        assertEquals("Dean", ((Name) n1.get()).firstName);  //获取元素后要自己转换
    }

}

可以在Java中使用Scala的元组,但是没有语法糖了。

public class ScalaTuples{
    public static void main(String[] args){
        Tuple2 tuple=new Tuple2<String,Integer>("one",2);

        System.out.println(tuple);
    }
}

但是在Java中使用FunctionN类型会失败,因为编译器不会自动合成隐藏的成员。

public class ScalaFunctions{
    public static void main(String[] args){
        Function1 strToInt=new Function1<String,Integer>(){
            public Integer apply(String s){
                Integer.parseInt(s);
            }
        }

        System.out.println(strToInt("101"));
    }
}

编译器会报错,提示抽象方法 apply$mcVJ$sp(long) 未定义。Scala 编译器会为我们自动生成,但 Java 编译器则不会。 如果想从 Java 调用 Scala 的 API,那就不能调用高阶方法,高阶方法即这些方法的参数或返回值是一个函数。

JavaBean

Scala 为了支持统一访问原则,并没有遵循 JavaBean 对字段读写方法的约定。 Scala 通过一个可以应用在字段上的标记 @scala.beans.BeanProperty (http://www.scala-lang.org/api/current/scala/beans/BeanProperty.html )解决 了这个问题,该标记告诉编译器生成 JavaBean 风格的 getter 和 setter 方法。此外,scala.beans 包(http://www.scala- lang.org/api/current/scala/beans/package.html )还包含其他用于配置 bean 属性的标记。

case class ComplexBean(
@scala.beans.BeanProperty real: Double, @scala.beans.BeanProperty imaginary: Double) 
    def +(that: ComplexBean) =
        new ComplexBean(real + that.real, imaginary + that.imaginary)
    def -(that: ComplexBean) =
        new ComplexBean(real - that.real, imaginary - that.imaginary)
}

因为这些字段是不可变的,这里没有 setter 方法。与此相反,对原版 Complex 做反编译,只会得到 real() 方法和 imaginary() 方法。即使 使用了 BeanProperty 标记,你得到的仍然是普通的读方法和可能的写方法。

AnyVal类型和Java原生类型

所有 AnyVal 类型被转换为它们相应的 Java 原生类 型。特别的是,Unit 被映射为 void 类型。

Java代码中的Scala名称

Scala 对标识符的限定更灵活,例如:* 、< 等 Scala 操作符在字节码中不允许用来做标识符。因此,这些字符经过编码(或称为“变 形”,mangled),以满足 JVM 的限制。

操作 编码结果 操作 编码结果 操作 编码结果 操作 编码结果
= $eq > $greater < $less    
+ $plus - $minus * $times / $div
\ $bslash | $bar ! $bang ? $qmakrk
: $colon % $parcent ^ $up & $amp

小结

在所有程序没有整体替换成为Scala的情况下,Scala和Java的互操作在所难免,在Java成为主流的情况下,一步步的处理程序代码的替换会好很多。

Show Disqus Comments

Search

    Table of Contents