UDN-企业互联网技术人气社区

板块导航

浏览  : 1216
回复  : 0

[讨论交流] 变参调用:scala和java的一个不同点

[复制链接]
呵呵燕的头像 楼主
发表于 2016-11-13 15:27:30 | 显示全部楼层 |阅读模式
  scala和java几乎没有区别,可以互相调用。注意这里说的是几乎,总有那么少数,出人意料的惊喜在告诉你,scala就是scala。

  一个例子

  1. import com.alibaba.fastjson.JSON
  2. object test {
  3.   def main(args: Array[String]) = {
  4.     val map = new util.HashMap[CharSequence, CharSequence]()
  5.     map.put("123", "22333")
  6.     map.put("test", null)
  7.     val ret = JSON.toJSONString(map)
  8.     println(ret)
  9.    }
  10. }
复制代码


  如上所示,这个例子很简单,把一个jabva的map转换成json字符串。

  其中JSON.toJSONString的代码如下:

  1. public static String toJSONString(Object object) {
  2.     return toJSONString(object, emptyFilters, new SerializerFeature[0]);
  3. }
  4. public static String toJSONString(Object object, SerializerFeature... features) {
  5.     return toJSONString(object, DEFAULT_GENERATE_FEATURE, features);
  6. }
复制代码


  问题来了,上面的测试用例报错了:

  1. ambiguous reference to overloaded definition,both method toJSONString in object JSON of
  2. type (x$1: Any, x$2: com.alibaba.fastjson.serializer.SerializerFeature*)String
  3. and method toJSONString in object JSON of
  4. type (x$1: Any)String
  5. match argument types (java.util.HashMap[CharSequence,CharSequence])
  6. val ret = JSON.toJSONString(map)
复制代码


  错误的原因很明显,编译器在编译scala调用java依赖包里面的toJSONString函数时发生了歧义。

  scala含有变参的重载函数

  看一段代码:

  1. object Foo {
  2.   def apply (x1: Int): Int = 2
  3.   def apply (x1: Int, x2: Int*): Int = 3
  4.   def apply (x1: Int*): Int = 4
  5. }
  6. object Test11 extends App {
  7.   Console println Foo(7)
  8.   Console println Foo(2, Array(3).toSeq: _*)
  9.   Console println Foo(Array(3, 4).toSeq: _*)
  10. }
复制代码


  上述代码分别输出:2、3、4

  对于前两个构造函数,刚好对应了文章开头的例子,说明,scala调用类似的scala依赖是没有问题的。

  我们来注意一下scala如何调用变参:当你使用Foo(2, 3)调用时候,会出现歧义,因为(2, 3)可以匹配到第二个和第三个构造函数。所以,就只能用看起来很奇怪的写法Foo(2, Array(3).toSeq: _*)来进行区分。Array(3).toSeq: _*就是在告诉编译器,这个参数是变参的,别匹配错了。

  然后,我们来看看Java怎么做的。

  java含有变参的重载函数

  代码就不写了,总之,java调用java类似的函数也是没有问题的。

  那么问题来了,为什么scala调用java类似的函数就有问题呢?要回答这个问题,我们先来看看java在进行重载调用时,编译器都做了些啥?

  调用方法时,能与固定参数函数以及可变参数都匹配时,优先调用固定参数方法。

  调用方法时,两个变长参数都匹配时,编译无法通过。

  1.  public class VariVargsTest2 {
  2.   public static void main(String[] args) {
  3.    test("hello"); //1
  4.   }
  5.   public static void test(String ...args)
  6.   {
  7.     System.out.println("变长参数1");
  8.   }
  9.   public static void test(String string,String...args)
  10.   {
  11.     System.out.println("变长参数2");
  12.   }
  13. }
复制代码


  当没有1处代码时,程序是能够编译通过的。但是当添加了1处代码后无法通过编译,给出的错误是:The method test(String[]) is ambiguous for the type VariVargsTest2。编译器不知道选取哪个方法。

  总结

  从scala和java对含有变参的重载函数处理的方式上,我们可以知道文章开头的代码为什么编译不过。

  scala首先会自己匹配,自己匹配不了的时候,使用者可以手动来标识变参参数。

  java自己匹配,并有一个自己的调用优先级顺序,实在分不清就编译不过了。

  回到开头的问题,scala调用java出问题了,就应该是scala编译器和java编译器在处理这个问题时的差异导致的吧。

  参考文献

  [1] Java语法糖初探(三)–变长参数

原文作者:佚名  来源:开发者头条

相关帖子

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部