Scala入门到精通——第二十八节 Scala与JAVA互操作
来源:互联网 发布:excel数据左上角 编辑:程序博客网 时间:2024/05/18 19:43
本节主要内容
- JAVA中调用Scala类
- Scala中调用JAVA类
- Scala类型参数与JAVA泛型互操作
- Scala与Java间的异常处理互操作
1. JAVA中调用Scala类
Java可以直接操作纵Scala类,如同scala直接使用Java中的类一样,例如:
//在Person.scala文件中定义Scala语法的Person类package cn.scala.xtwy.scalaToJavaclass Person(val name:String,val age:Int)//伴生对象object Person{ def getIdentityNo()= {"test"}}//ScalaInJava.java文件中定义了ScalaInJava类//直接调用Scala中的Person类package cn.scala.xtwy.scalaToJava;public class ScalaInJava { public static void main(String[] args) { Person p=new Person("摇摆少年梦", 27); System.out.println("name="+p.name()+" age="+p.age()); //伴生对象的方法当做静态方法来使用 System.out.println(Person.getIdentityNo()); }}
对!就是这么简单,Java似乎可以无缝操纵Scala语言中定义的类,在trait那一节中我们提到,如果trait中全部是抽象成员,则它与java中的interface是等同的,这时候java可以把它当作接口来使用,但如果trait中定义了具体成员,则它有着自己的内部实现,此时在java中使用的时候需要作相应的调整。我们先看下trait中全部是抽象成员的情况,例如:
//全部是抽象成员,与java的interface等同trait MySQLDAO{ def delete(id:String):Boolean def add(o:Any):Boolean def update(o:Any):Int def query(id:String):List[Any]}//MySQLDAO字节码反编译后的结果D:\ScalaWorkspace\ScalaChapter28\bin\cn\scala\xtwy\scalaToJava>javap MySQLDAO.classCompiled from "MySQLDAO.scala"public interface cn.scala.xtwy.scalaToJava.MySQLDAO { public abstract boolean delete(java.lang.String); public abstract boolean add(java.lang.Object); public abstract int update(java.lang.Object); public abstract scala.collection.immutable.List<java.lang.Object> query(java.lang.String);}//java直接implement,与普通的java接口一样public class MySQLDAOImpl implements MySQLDAO{ @Override public boolean delete(String id) { // TODO Auto-generated method stub return false; } @Override public boolean add(Object o) { // TODO Auto-generated method stub return false; } @Override public int update(Object o) { // TODO Auto-generated method stub return 0; } @Override public List<Object> query(String id) { // TODO Auto-generated method stub return null; }}
那如果Trait中包括了具体的成员,此时又该怎么使用呢?此时需要作特殊处理,代码如下:
/** * Created by 摇摆少年梦 on 2015/8/16. */trait MySQLDAO { //具体方法 def delete(id:String):Boolean={ true} def add(o:Any):Boolean def update(o:Any):Int def query(id:String):List[Any] }//JAVA语言实现带有具体成员方法的MySQLDAO /** * Created by 摇摆少年梦 on 2015/8/16. */public class MySQLDAOImpl implements MySQLDAO { @Override public boolean delete(String id) { //调用生成带有具体delete方法实现的MySQLDAO$class if (MySQLDAO$class.delete(this, id)) return true; else return false; } @Override public boolean add(Object o) { return false; } @Override public int update(Object o) { return 0; } @Override public List<Object> query(String id) { return null; }}
用javap命令查看带具体成员方法的trait MySQLDAO时,其代码是一样的
D:\ScalaIntellijIDEAWorkSpace\out\production\ScalaChapter28\cn\scala\xtwy\JavaRevokeScala>javap MySQLDAO$class.classCompiled from "MySQLDAO.scala"public abstract class cn.scala.xtwy.JavaRevokeScala.MySQLDAO$class { public static boolean delete(cn.scala.xtwy.JavaRevokeScala.MySQLDAO, java.lang.String); public static void $init$(cn.scala.xtwy.JavaRevokeScala.MySQLDAO);}D:\ScalaIntellijIDEAWorkSpace\out\production\ScalaChapter28\cn\scala\xtwy\JavaRevokeScala>javap MySQLDAO.classCompiled from "MySQLDAO.scala"public abstract class cn.scala.xtwy.JavaRevokeScala.MySQLDAO$class { public static boolean delete(cn.scala.xtwy.JavaRevokeScala.MySQLDAO, java.lang.String); public static void $init$(cn.scala.xtwy.JavaRevokeScala.MySQLDAO);}
但其实并不是这样的,经本人查阅相关资料发现,可能是scala版本原因导致的,这篇文献中提到的跟实际情况应该是稳合的http://www.importnew.com/6188.html
这篇文章中给出了下面这样一个trait的定义:
trait MyTrait { def traitName:String def upperTraitName = traitName.toUpperCase}
它生成下面两个字节码文件MyTrait.class、MyTrait$class
[local ~/projects/interop/target/scala_2.8.1/classes/com/twitter/interop]$ javap MyTraitCompiled 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 MyTrait$classCompiled 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);}
这种情况应该是跟实际情况稳合的,trait MyTrait会自动生成一个名为MyTrait的interface,MyTrait$class的抽象类。我们可以看到,该作者的scala版本是2.8.1,而我们的scala版本是2.10.4,至于为什么出现这样的原因,本人暂时还没有弄清楚,但可以肯定的是,http://www.importnew.com/6188.html这篇文章讲的内容跟实际是稳合的,因为前面的MySQLDAOImpl仍然是实现MySQLDAO接口方式定义的,但在重写delete方法时采用的是
@Override public boolean delete(String id) { //调用生成带有具体delete方法实现的MySQLDAO$class if (MySQLDAO$class.delete(this, id)) return true; else return false; }
这种方式进行方法的实现,即MySQLDAO$class是个抽象类,该抽象类中包含了MySQLDAO中实现的方法。也即
trait MySQLDAO { //具体方法 def delete(id:String):Boolean={ true} def add(o:Any):Boolean def update(o:Any):Int def query(id:String):List[Any] }
最终反编译后的代码应该具有以下形式:
public cn.scala.xtwy.JavaRevokeScala.MySQLDAO extends scala.ScalaObject{ public abstract boolean delete(java.lang.String); public abstract boolean add(java.lang.Object); public abstract int update(java.lang.Object); public abstract scala.collection.immutable.List<java.lang.Object> query(java.lang.String);}
值得注意的是在Scala IDE for Eclipse中不能实现下列代码的调用
@Override public boolean delete(String id) { //调用生成带有具体delete方法实现的MySQLDAO$class if (MySQLDAO$class.delete(this, id)) return true; else return false; }
只有在Intellij IDEA中才能正确使用,从这点上也说明了Intellij IDEA在编写scala应用程序时更贴近实际。
2. Scala中调用JAVA类
Scala可以直接调用Java实现的任何类,只要符合scala语法就可以,不过某些方法在JAVA类中不存在,但在scala中却存在操作更简便的方法,例如集合的foreach方法,在java中是不存在的,但我们想用的话怎么办呢?这时候可以通过隐式转换来实现,scala已经为我们考虑到实际应用场景了,例如:
import java.util.ArrayList;/** * Created by 摇摆少年梦 on 2015/8/16. */class RevokeJavaCollections { def getList={ val list=new ArrayList[String]() list.add("摇摆少年梦") list.add("学途无忧网金牌讲师") list } def main(args: Array[String]) { val list=getList //因为list是java.util.ArrayList类型,所以下这条语句编译不会通过 list.foreach(println) }}
此时只要引入scala.collection.JavaConversions._包就可以了,它会我们自动地进行隐式转换,从而可以使用scala中的一些非常方便的高阶函数,如foreach方法,代码如下:
package cn.scala.xtwy.ScalaRevokeJavaimport java.util.ArrayList;//引入下面这条语句后便可以调用scala集合中的方法,如foreach,map等import scala.collection.JavaConversions._/** * Created by 摇摆少年梦 on 2015/8/16. */object RevokeJavaCollections{ def getList={ val list=new ArrayList[String]() list.add("摇摆少年梦") list.add("学途无忧网金牌讲师") list } def main(args: Array[String]) { val list=getList //现在可以调用scala集合中的foreach等方法了 list.foreach(println) val list2=list.map(x=>x*2) println(list2) }}
前面我们使用的是隐式转换,我们还可以显式地进行转换,例如:
import java.util.ArrayList;import scala.collection.JavaConversions._/** * Created by 摇摆少年梦 on 2015/8/16. */object RevokeJavaCollections{ def getList={ val list=new ArrayList[String]() list.add("摇摆少年梦") list.add("学途无忧网金牌讲师") list } def main(args: Array[String]) { val list=getList list.foreach(println) val list2=list.map(x=>x*2) println(list2) //显式地进行转换 val listStr=asJavaIterable(JavaListString.getListString) for(i<- listStr) println(i) }}
下面给出的是Scala集合与Java集合支持的转换操作(取自JavaConversions源码):
/** A collection of implicit conversions supporting interoperability between * Scala and Java collections. * * The following conversions are supported: *{{{ //相互转换 * scala.collection.Iterable <=> java.lang.Iterable * scala.collection.Iterable <=> java.util.Collection * scala.collection.Iterator <=> java.util.{ Iterator, Enumeration } * scala.collection.mutable.Buffer <=> java.util.List * scala.collection.mutable.Set <=> java.util.Set * scala.collection.mutable.Map <=> java.util.{ Map, Dictionary } * scala.collection.mutable.ConcurrentMap (deprecated since 2.10) <=> java.util.concurrent.ConcurrentMap * scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap *}}} * In all cases, converting from a source type to a target type and back * again will return the original source object, eg. * *{{{//源类型到目标类型转换,再从转换回去,得到的是相同对象 * import scala.collection.JavaConversions._ * * val sl = new scala.collection.mutable.ListBuffer[Int] * val jl : java.util.List[Int] = sl * val sl2 : scala.collection.mutable.Buffer[Int] = jl * assert(sl eq sl2) *}}} * In addition, the following one way conversions are provided: * *{{{ //只支持单向转换的类 * scala.collection.Seq => java.util.List * scala.collection.mutable.Seq => java.util.List * scala.collection.Set => java.util.Set * scala.collection.Map => java.util.Map * java.util.Properties => scala.collection.mutable.Map[String, String] *}}} * * @author Miles Sabin * @author Martin Odersky * @since 2.8 */
3. Scala类型参数与JAVA泛型互操作
Java中的泛型可以直接转换成Scala中的泛型,在前面的课程中我们已经有所涉及,例如Java中的Comparator<T>
可以直接转换成 Scala中的Comparator[T]
使用方法完全一样,不同的只是语法上的。下列代码给出了其使用方法:
package cn.scala.xtwy.JavaAndScalaGenericimport java.util._/** * Created by 摇摆少年梦 on 2015/8/16. */case class Person(val name:String,val age:Int)//在Java中Comparator是这么用的:Comparator<Person>//而在Scala中,是这么用的:Comparator[Person]class PersonComparator extends Comparator[Person]{ override def compare(o1: Person, o2: Person): Int = if(o1.age>o2.age) 1 else -1}object ScalaUseJavaComparator extends App{ val p1=Person("摇摆少年梦",27) val p2=Person("李四",29) val personComparator=new PersonComparator() if(personComparator.compare(p1,p2)>0) println(p1) else println(p2)}
下面的代码演示了Java是如何使用Scala中的泛型的:
package cn.scala.xtwy.JavaAndScalaGenericimport scala.beans.BeanProperty/** * Created by 摇摆少年梦 on 2015/8/16. */ //Student类用泛型定义,成员变量name及age指定泛型参数 //并且用注解的方式生成JavaBean规范的getter方法 //因为是val的,所以只会生成getter方法class Student[T,S](@BeanProperty val name:T,@BeanProperty val age:S){}package cn.scala.xtwy.JavaAndScalaGeneric;/** * Created by 摇摆少年梦 on 2015/8/16. */public class JavaUseScalaGeneric { public static void main(String[] args){ Student<String,Integer> student=new Student<String,Integer>("小李",18); //Scala版本的getter方法 System.out.println(student.name()); //JavaBean版本的getter方法 System.out.println(student.getName()); }}
通过上述代码,我们已经十分清楚了Scala中的泛型如何与Java中的泛型进行互操作了,但还有一个问题值得去考虑,那就是Java中的通配符的泛型如何与Scala中的泛型进行操作呢?例如:
package cn.scala.xtwy.JavaAndScalaGeneric;import java.util.ArrayList;import java.util.List;/** * Created by 摇摆少年梦 on 2015/8/16. */public class JavaWildcardGeneric { //Java的通配符类型,要接受任何类型 public static List<?> getList(){ List<String> listStr=new ArrayList<String>(); listStr.add("摇摆少年梦"); listStr.add("学途无忧网金牌讲师"); return listStr; }}package cn.scala.xtwy.JavaAndScalaGenericimport java.util.Listimport scala.collection.JavaConversions._/** * Created by 摇摆少年梦 on 2015/8/16. */class ScalaExistTypeToJavaWildcardGeneric1 { //采用Scala中的存在类型与Java中的能匹符泛型进行互操作 def printList(list: List[T] forSome {type T}):Unit={ //因为我们引入了import scala.collection.JavaConversions._ //所以可以直接调用foreach方法 list.foreach(println) } //上面的函数与下面的等同 def printList2(list: List[_]):Unit={ list.foreach(println) }}object Main extends App{ val s=new ScalaExistTypeToJavaWildcardGeneric1 s.printList(JavaWildcardGeneric.getList) s.printList2(JavaWildcardGeneric.getList)}
4. Scala与Java间的异常处理互操作
Java中的异常处理具有如下形式:
package cn.scala.xtwy.ScalaAndJavaException;import java.io.File;import java.io.IOException;/** * Created by 摇摆少年梦 on 2015/8/16. */public class JavaExceiptionDemo { public static void main(String[] args) { File file = new File("a.txt"); if (!file.exists()) { try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } }}
Scala中的异常处理是通过模式匹配来实现的,代码如下:
package cn.scala.xtwy.ScalaAndJavaExceptionimport java.io.File/** * Created by 摇摆少年梦 on 2015/8/16. */object ScalaExceptionDemo extends App{ val file: File = new File("a.txt") if (!file.exists) { try { file.createNewFile } catch { //通过模式匹配来实现异常处理 case e: IOException => { e.printStackTrace } } }}
上面给的例子是Scala如何捕获Java中抛出的异常,下面的例子给出的是Java如何捕获Scala中声明的异常,代码如下:
package cn.scala.xtwy.ScalaAndJavaExceptionclass ScalaThrower { //Scala利用注解@throws声明抛出异常 @throws(classOf[Exception]) def exceptionThrower { throw new Exception("Exception!") }}//Java中调用ScalaThrower(Scala类),然后捕获其抛出的异常public class JavaCatchScalaThrower { public static void main(String[] args){ ScalaThrower st=new ScalaThrower(); try{ st.exceptionThrower(); }catch (Exception e){ e.printStackTrace(); } }}
通过本节,我们基本能掌握Scala与Java的互操作,当然这里面还有很多内容没有涉及,但在日常开发工作当中,掌握本节讲的内容便可以应付绝大多数互操作问题。
- Scala入门到精通——第二十八节 Scala与JAVA互操作
- Scala入门到精通——第二十八节 Scala与JAVA互操作
- 第二十八节 Scala与JAVA互操作
- Scala入门到精通——第十八节 隐式转换与隐式参数(一)
- Scala入门到精通——第十八节 隐式转换与隐式参数(一)
- Scala入门到精通——第八节 包和引入
- Scala入门到精通——第八节 包和引入
- Scala入门到精通——第二十节 类型参数(二)
- Scala入门到精通——第二十五节 提取器(Extractor)
- Scala入门到精通——第二十节 类型参数(二)
- Scala入门到精通——第二十五节 提取器(Extractor)
- Scala入门到精通——第九节 继承与组合
- Scala入门到精通——第九节 继承与组合
- Scala入门到精通——第九节 继承与组合
- Scala入门到精通——第一节 Scala语言初步
- Scala入门到精通——第一节 Scala语言初步
- Scala入门到精通——第一节 Scala语言初步
- Scala入门到精通—— 第二节Scala基本类型及操作、程序控制结构
- Android跳转系统应用
- 黑幕背后的Autorelease
- Python笔记
- footer至于底部的四种方法
- NSValue对任何结构体,基本类型,指针的封装
- Scala入门到精通——第二十八节 Scala与JAVA互操作
- 访问控制符
- 微信检测工具 微信筛选技巧
- 在Swift中检查API的可用性
- Linux arm tftp 以及nfs 的调试方法使用
- Swift 多范式编程语言(对象,函数,协议)
- sklearn集成方法之一随机森林
- 从VC6升级到vs2010需要修改的部分经验交流
- KVO原理及知识点(swift2.0)