课程内容涵盖了Java互操作性。

  • Javap
  • 异常
  • 特质
  • 单例对象
  • 闭包和函数
  • 变化性

Javap

javap的是JDK附带的一个工具。不是JRE,这里是有区别的。 javap反编译类定义,给你展示里面有什么。用法很简单

[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  时要考虑的四个要点

  • 类参数
  • 类常量
  • 类变量
  • 异常

我们将构建一个简单的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构造函数的参数。这意味着你不能从类的外部访问。
  • 声明一个类参数为val/var 和这段代码是相同的
class SimpleClass(acc_: String) {
val acc = acc_
}

这使得它在Java代码中就像其他常量一样可以被访问

类常量

  • 常量(val)在Java中定义了一个获取方法。你可以通过方法“foo()”访问“val foo”的值

类变量

  • 变量(var)会生成一个 _$eq 方法。你可以这样调用它
foo$_eq("newfoo");

BeanProperty

你可以通过@BeanProperty注解val和var定义。这会按照POJO定义生成getter/setter方法。如果你想生成isFoo方法,使用BooleanBeanProperty注解。丑陋的foo$_eq将变为

setFoo("newfoo");
getFoo();

异常

Scala没有像java那样有受检异常(checked exception)。需不需要受检异常是一个我们不会进入的哲学辩论,不过当你需要在Java中捕获它时就 很重要 了。dangerFoo和dangerBar将演示这一点。在Java中不能这样做

        // exception erasure!
try {
s.dangerFoo();
} catch (IOException e) {
// UGLY
}

Java会抱怨说 s.dangerFoo从未抛出过 IOException异常。我们可以通过捕获Throwable来跳过,但是这样不好。

相反,作为一个良好的Scala公民,可以很体面地像在dangerBar中那样使用throws注解。这使我们能够继续在Java中使用受检异常。

进一步阅读

支持Java互操作的Scala注解的完整列表在这里 http://www.scala-lang.org/node/106

特质

你如何获得一个接口+实现?让我们看一个简单的特质定义

trait MyTrait {
def traitName:String
def upperTraitName = traitName.toUpperCase
}

这个特质有一个抽象方法(traitName)和一个实现的方法(upperTraitName)。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{
public abstract java.lang.String traitName();
public abstract java.lang.String upperTraitName();
}

MyTrait$class更有趣

[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中来扩展一个特质的提示。

首先尝试下面的操作

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;
}
}

我们会得到以下错误

[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] ^

我们 可以 自己实现。但有一个鬼鬼祟祟的方式。

package com.twitter.interop;

    public String upperTraitName() {
return MyTrait$class.upperTraitName(this);
}

我们只要把调用代理到生成的Scala实现上就可以了。如果愿意我们也可以覆盖它。

单例对象

单例对象是Scala实现静态方法/单例模式的方式。在Java中使用它会有点奇怪。没有一个使用它们的完美风格,但在Scala2.8中用起来并不很糟糕

一个Scala单例对象会被编译成由“$”结尾的类。让我们创建一个类和一个伴生对象

class TraitImpl(name: String) extends MyTrait {
def traitName = name
} object TraitImpl {
def apply = new TraitImpl("foo")
def apply(name: String) = new TraitImpl(name)
}

我们可以像这样天真地在Java中访问

MyTrait foo = TraitImpl$.MODULE$.apply("foo");

现在你可能会问自己,这是神马玩意?这是一个正常的反应。让我们来看看TraitImpl$里面实际上是什么

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$的静态成员。方法实现被委托给该成员。这使得访问代码很难看,但却是可行的。

转发方法(Forwarding Methods)

在Scala2.8中处理单例对象变得相对容易一点。如果你有一个类与一个伴生对象,2.8编译器会生成转发方法在伴生类中。所以,如果你用2.8,你可以像这样调用TraitImpl单例对象的方法

MyTrait foo = TraitImpl.apply("foo");

闭包函数

Scala的最重要的特点之一,就是把函数作为头等公民。让我们来定义一个类,它定义了一些以函数作为参数的方法。

class ClosureClass {
def printResult[T](f: => T) = {
println(f)
} def printResult[T](f: String => T) = {
println(f("HI THERE"))
}
}

在Scala中可以像这样调用

val cc = new ClosureClass
cc.printResult { "HI MOM" }

在Java中却不那么容易,不过也并不可怕。让我们来看看ClosureClass实际上被编译成什么:

[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,像这样

    @Test public void closureTest() {
ClosureClass c = new ClosureClass();
c.printResult(new AbstractFunction0() {
public String apply() {
return "foo";
}
});
c.printResult(new AbstractFunction1<String, String>() {
public String apply(String arg) {
return arg + "foo";
}
});
}

注意我们可以使用泛型参数。

与Java互操作的更多相关文章

  1. LuaJavaBridge - Lua 与 Java 互操作的简单解决方案

    http://dualface.github.io/blog/2013/01/01/call-java-from-lua/ 最近在游戏里要集成中国移动的 SDK,而这些 SDK 都是用 Java 编写 ...

  2. 快学Scala 第五课 (构造映射,获取映射值,更新映射值,迭代映射,与Java互操作)

    构造映射: val score = Map[String, Int]() val score1 = HashMap[String, Int]() val value1 = Map[String, In ...

  3. Php AES加密、解密与Java互操作的问题

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...

  4. LuaJavaBridge - lua与java互操作的简单解决方案

    引入:Android平台代码和Lua代码的交互均通过C++和Java交互,Lua再和C++交互(lua  <==> C++ <==> java) 我最开始遇见这种lua调用ja ...

  5. CCLuaObjcBridge - Lua 与 Objective-C 互操作的简单解决方案

    http://dualface.github.io/blog/2013/01/27/call-objectivec-from-lua/ 月初的时候,发了一篇关于 Lua 与 Java 互操作的文章,里 ...

  6. 给Java开发者的Scala教程

    author:Michel Schinz,Philipp Haller 1. 简介 本文将该要的介绍Scala语言和其编译.这里假设读者已经有一定的java开发经验,需要概要的了解他们可以用Scala ...

  7. lua调用java java调用lua[转载]

    转载:http://dualface.github.io/blog/2013/01/01/call-java-from-lua/LuaJavaBridge - Lua 与 Java 互操作的简单解决方 ...

  8. Kotlin开发语言文档(官方文档)-- 目录

    开始阅读Kotlin官方文档.先上文档目录.有些内容还未阅读,有些目录标目翻译还需琢磨琢磨.后续再将具体内容的链接逐步加上. 文档链接:https://kotlinlang.org/docs/kotl ...

  9. Scala学习(一)

    最近在学习Scala,总结了一下比较基础的知识. 一.Scala简介 1.Scalable Language,是一门多范式的编程语言,是一种纯面向对象的语言,每个值都是对象. 2.特点:①Scalab ...

随机推荐

  1. Web API

    https://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api ...

  2. windows server 2012 r2 远程桌面连接指南

    具体详情请阅览文档  http://pan.baidu.com/s/1jHTCpW6 windows server 2012 r2 远程桌面连接指南 - 作者 rick·bao - 日期 2016-0 ...

  3. 超炫数字特效动画AE模板

    下载方式: 网盘地址+迅雷地址+迅雷地址+备份地址 <ignore_js_op> 本AE模板是由Videohive机构出品的超炫数字特效动画AE模板,Videohive The Numbe ...

  4. FAQ

    1.Baudrare and the speed of Byte. 2. Linux FS and Flash store. 3. SW's Coupling. 4. Protocol and Pro ...

  5. MySQL环境部署

    阅读目录: 1.Windows下安装MySQL 2.Linux下安装MySQL 序章: MySQL是个小型的数据库,用来自己做小项目,做学习练习什么的再适合不过了,不过新手总会被一些莫名奇妙的问题难住 ...

  6. MultipeerConnectivity框架,近场通信的基本使用

    Multipeer connectivity是一个使附近设备通过Wi-Fi网络.P2P Wi-Fi以及蓝牙个人局域网进行通信的框架.互相链接的节点可以安全地传递信息.流或是其他文件资源,而不用通过网络 ...

  7. TCP/IP协议学习(五) 基于C# Socket的C/S模型

    TCP/IP协议作为现代网络通讯的基石,内容包罗万象,直接去理解理论是比较困难的:然而通过实践先理解网络通讯的理解,在反过来理解学习TCP/IP协议栈就相对简单很多.C#通过提供的Socket API ...

  8. Deep Learning 18:DBM的学习及练习_读论文“Deep Boltzmann Machines”的笔记

    前言 论文“Deep Boltzmann Machines”是Geoffrey Hinton和他的大牛学生Ruslan Salakhutdinov在论文“Reducing the Dimensiona ...

  9. java: system.gc()和垃圾回收机制finalize

    System.gc()和垃圾回收机制前的收尾方法:finalize(收尾机制) 程序退出时,为每个对象调用一次finalize方法,垃圾回收前的收尾方法 System.gc() 垃圾回收方法 clas ...

  10. WPF中RDLC报表的钻取实现

    1.新建wpf项目,并引入3个程序集: Microsoft.ReportViewer.WinForms WindowsFormsIntegration System.Windows.Forms 如果无 ...