知识大全 面向Java开发人员的Scala指南: 关于特征和行为

Posted 特征

篇首语:莫道桑榆晚,为霞尚满天。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 面向Java开发人员的Scala指南: 关于特征和行为相关的知识,希望对你有一定的参考价值。

面向Java开发人员的Scala指南: 关于特征和行为  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  摘要 Scala 并不仅仅只给 JVM 引入了函数概念 它还为我们提供了一种对于面向对象语言设计的现代视角 在这一期的 面向 Java 开发人员的 Scala 指南 中 Ted Neward 介绍了 Scala 如何利用特征(trait)使对象更加简单 更易于构建 您将了解到 特征与 Java? 接口和 C++ 多重继承提供的传统极性既有相似之处 也有不同之处

  著名科学家 研究学者艾萨克 牛顿爵士有这样一句名言 如果说我看得比别人远一些 那是因为我站在巨人的肩膀上 作为一名热心的历史和政治学家 我想对这位伟人的名言略加修改 如果说我看得比别人远一些 那是因为我站在历史的肩膀上 而这句话又体现出另一位历史学家 Gee Santayana 的名言 忘记历史必将重蹈覆辙 换句话说 如果我们不能回顾历史 从过去的错误(包括我们自己过去的经验)中吸取教训 就没有机会做出改进

  您可能会疑惑 这样的哲学与 Scala 有什么关系?继承就是我们要讨论的内容之一 考虑这样一个事实 Java 语言的创建已经是近 年前的事情 当时是 面向对象 的全盛时期 它设计用于模仿当时的主流语言 C++ 尝试将使用这种语言的开发人员吸引到 Java 平台上来 毫无疑问 在当时看来 这样的决策是明智而且必要的 但回顾一下 就会发现其中有些地方并不像创建者设想的那样有益

  例如 在二十年前 对于 Java 语言的创建者来说 反映 C++ 风格的私有继承和多重继承是必要的 自那之后 许多 Java 开发人开始为这些决策而后悔 在这一期的 Scala 指南中 我回顾了 Java 语言中多重继承和私有继承的历史 随后 您将看到 Scala 是怎样改写了历史 为所有人带来更大收益

  C++ 和 Java 语言中的继承

  C++ 工作的人们能够回忆起 私有继承是从基类中获取行为的一种方法 不必显式地接受 IS A 关系 将基类标记为 私有 允许派生类从该基类继承而来 而无需实际成为 一个基类 但对自身的私有继承是未得到广泛应用的特性之一 继承一个基类而无法将它向下或向上转换到基类的理念是不明智的

  另一方面 多重继承往往被视为面向对象编程的必备要素 在建模交通工具的层次结构时 SeaPlane 无疑需要继承 Boat(使用其 startEngine() 和 sail() 方法)以及 Plane(使用其 startEngine() 和 fly() 方法) SeaPlane 既是 Boat 也是 Plane 难道不是吗?

  无论如何 这是在 C++ 鼎盛时期的想法 在快速转向 Java 语言时 我们认为多重继承与私有继承一样存在缺陷 所有 Java 开发人员都会告诉您 SeaPlane 应该继承 Floatable 和 Flyable 接口(或许还包括 EnginePowered 接口或基类) 继承接口意味着能够实现该类需要的所有方法 而不会遇到 虚拟多重继承 的难题(遇到这种难题时 要弄清楚在调用 SeaPlane 的 startEngine() 方法时应调用哪个基类的 startEngine())

  遗憾的是 彻底放弃私有继承和多重继承会使我们在代码重用方面付出昂贵的代价 Java 开发人员可能会因从虚拟多重继承中解放出来而高兴 但代价是程序员往往要完成辛苦而易于出错的工作

  

  关于本系列

  Ted Neward 将和您一起深入探讨 Scala 编程语言 在这个新的 developerWorks 系列 中 您将深入了解 Sacla 并在实践中看到 Scala 的语言功能 进行比较时 Scala 代码和 Java 代码将放在一起展示 但(您将发现)Scala 中的许多内容与您在 Java 编程中发现的任何内容都没有直接关联 而这正是 Scala 的魅力所在!如果用 Java 代码就能够实现的话 又何必再学习 Scala 呢?

  回顾可重用行为

  规范是 Java 平台的基础 它带来了众多 Java 生态系统作为依据的 POJO 我们都明白一点 Java 代码中的属性由 get()/set() 对管理 如清单 所示

  清单 Person POJO

   //This is Java      public class Person    private String lastName;    private String firstName;    private int age;        public Person(String fn String ln int a)            lastName = ln; firstName = fn; age = a;            public String getFirstName() return firstName;     public void setFirstName(String v) firstName = v;     public String getLastName() return lastName;     public void setLastName(String v) lastName = v;     public int getAge() return age;     public void setAge(int v) age = v;

  这些代码看起来非常简单 编写起来也不难 但如果您希望提供通知支持 — 使第三方能够使用 POJO 注册并在变更属性时接收回调 事情会怎样?根据 JavaBeans 规范 必须实现 PropertyChangeListener 接口以及它的一个方法 propertyChange() 如果您希望允许任何 POJO 的 PropertyChangeListener 都能够对属性更改 投票 那么 POJO 就需要实现 VetoableChangeListener 接口 该接口的实现又依赖于 vetoableChange() 方法的实现

  至少 事情应该是这样运作的

  实际上 希望成为属性变更通知接收者的用户必须实现 PropertyChangeListener 接口 发送者(本例中的 Person 类)必须提供接收该接口实例的公共方法和监听器需要监听的属性名称 最终得到更加复杂的 Person 如清单 所示

  清单 Person POJO 第 种形式

   //This is Java      public class Person    // rest as before except that inside each setter we have to do something    // like:    // public setFoo(T newValue)    //     //     T oldValue = foo;    //     foo = newValue;    //     pcs firePropertyChange( foo oldValue newValue);    //         public void addPropertyChangeListener(PropertyChangeListener pcl)            // keep a reference to pcl        public void removePropertyChangeListener(PropertyChangeListener pcl)            // find the reference to pcl and remove it   

  保持引用属性变更监听器意味着 Person POJO 必须保留某种类型的集合类(例如 ArrayList)来包含所有引用 然后必须实例化 插入并移除 POJO — 由于这些操作不是原子操作 因此还必须包含恰当的同步保护

  最后 如果某个属性发生变化 属性监听器列表必须得到通知 通常通过遍历 PropertyChangeListener 的集合并对各元素调用 propertyChange() 来实现 此过程包括传入新的 PropertyChangeEvent 描述属性 原有值和新值 这是 PropertyChangeEvent 类和 JavaBeans 规范的要求

  在我们编写的 POJO 中 只有少数支持监听器通知 这并不意外 在这里要完成大量工作 必须手动地重复处理所创建的每一个 JavaBean/POJO

  除了工作还是工作 — 变通方法在哪里?

  有趣的是 C++ 对于私有继承的支持在 Java 语言中得到了延续 今天 我们用它来解决 JavaBeans 规范的难题 一个基类为 POJO 提供了基本 add() 和 remove() 方法 集合类以及 firePropertyChanged() 方法 用于通知监听器属性变更

  我们仍然可以通过 Java 类完成 但由于 Java 缺乏私有继承 Person 类必须继承 Bean 基类 从而可向上转换 到 Bean 这妨碍了 Person 继承其他类 多重继承可能使我们不必处理后续的问题 但它也重新将我们引向了虚拟继承 而这是绝对要避免的

  针对这个问题的 Java 语言解决方案是运用众所周知的支持 类 在本例中是 PropertyChangeSupport 实例化 POJO 中的一个类 为 POJO 本身使用必要的公共方法 各公共方法都调用 Support 类来完成艰难的工作 更新后的 Person POJO 可以使用 PropertyChangeSupport 如下所示

  清单 Person POJO 第 种形式

   //This is Java      import java beans *;public class Person    private String lastName;    private String firstName;    private int age;    private PropertyChangeSupport propChgSupport =        new PropertyChangeSupport(this);        public Person(String fn String ln int a)            lastName = ln; firstName = fn; age = a;            public String getFirstName() return firstName;     public void setFirstName(String newValue)            String old = firstName;        firstName = newValue;        propChgSupport firePropertyChange( firstName old newValue);            public String getLastName() return lastName;     public void setLastName(String newValue)            String old = lastName;        lastName = newValue;        propChgSupport firePropertyChange( lastName old newValue);            public int getAge() return age;     public void setAge(int newValue)            int old = age;        age = newValue;        propChgSupport firePropertyChange( age old newValue);        public void addPropertyChangeListener(PropertyChangeListener pcl)            propChgSupport addPropertyChangeListener(pcl);        public void removePropertyChangeListener(PropertyChangeListener pcl)            propChgSupport removePropertyChangeListener(pcl);   

  不知道您有何感想 但这段代码的复杂得让我想去重拾汇编语言 最糟糕的是 您要对所编写的每一个 POJO 重复这样的代码序列 清单 中的半数工作都是在 POJO 本身中完成的 因此无法被重用 — 除非是通过传统的 复制粘贴 编程方法

  现在 让我们来看看 Scala 提供什么样内容来实现更好的变通方法

  Scala 中的特征和行为重用

  Scala 使您能够定义处于接口和类之间的新型结构 称为特征(trait) 特征很奇特 因为一个类可以按照需要整合许多特征 这与接口相似 但它们还可包含行为 这又与类相似 同样 与类和接口类似 特征可以引入新方法 但与类和接口不同之处在于 在特征作为类的一部分整合之前 不会检查行为的定义 或者换句话说 您可以定义出这样的方法 在整合到使用特征的类定义之前 不会检查其正确性

  特征听起来十分复杂 但一个实例就可以非常轻松地理解它们 首先 下面是在 Scala 中重定义的 Person POJO

  清单 Scala 的 Person POJO

   //This is Scalaclass Person(var firstName:String var lastName:String var age:Int)

  您还可以确认 Scala POJO 具备基于 Java POJO 的环境中需要的 get()/set() 方法 只需在类参数 firstName lastName 和 age 上使用 scala reflect BeanProperty 注释即可 现在 为简单起见 我们暂时不考虑这些方法

  如果 Person 类需要能够接收 PropertyChangeListener 可以使用如清单 所示的方式来完成此任务

  清单 Scala 的 Person POJO 与监听器

   //This is Scalaobject PCL    extends java beans PropertyChangeListener    override def propertyChange(pce:java beans PropertyChangeEvent):Unit =            System out println( Bean changed its + pce getPropertyName() +            from + pce getOldValue() +            to + pce getNewValue())    object App    def main(args:Array[String]):Unit =            val p = new Person( Jennifer Aloi )        p addPropertyChangeListener(PCL)                p setFirstName( Jenni )        p setAge( )                System out println(p)   

  注意 如何使用清单 中的 object 实现将静态方法注册为监听器 — 而在 Java 代码中 除非显式创建并实例化 Singleton 类 否则永远无法实现 这进一步证明了一个理论 Scala 从 Java 开发的历史 痛苦 中吸取了教训

  Person 的下一步是提供 addPropertyChangeListener() 方法 并在属性更改时对各监听器触发 propertyChange() 方法调用 在 Scala 中 以可重用的方式完成此任务与定义和使用特征一样简单 如清单 所示 我将此特征称为 BoundPropertyBean 因为在 JavaBeans 规范中 已通知 的属性称为绑定属性

  清单 神圣的行为重用!

   //This is Scalatrait BoundPropertyBean    import java beans _    val pcs = new PropertyChangeSupport(this)        def addPropertyChangeListener(pcl : PropertyChangeListener) =        pcs addPropertyChangeListener(pcl)        def removePropertyChangeListener(pcl : PropertyChangeListener) =        pcs removePropertyChangeListener(pcl)        def firePropertyChange(name : String oldVal : _ newVal : _) : Unit =        pcs firePropertyChange(new PropertyChangeEvent(this name oldVal newVal))

  同样 我依然要使用 java beans 包的 PropertyChangeSupport 类 不仅因为它提供了约 % 的实现细节 还因为我所具备的行为与直接使用它的 JavaBean/POJO 相同 对 Support 类的其他任何增强都将传播到我的特征 不同之处在于 Person POJO 不需要再直接使用 PropertyChangeSupport 如清单 所示

  清单 Scala 的 Person POJO 第 种形式

   //This is Scalaclass Person(var firstName:String var lastName:String var age:Int)    extends Object    with BoundPropertyBean    override def toString = [Person: firstName= + firstName +        lastName= + lastName + age= + age + ]

  在编译后 简单查看 Person 定义即可发现它有公共方法 addPropertyChangeListener() removePropertyChangeListener() 和 firePropertyChange() 就像 Java 版本的 Person 一样 实际上 Scala 的 Person 版本仅通过一行附加的代码即获得了这些新方法 类声明中的 with 子句将 Person 类标记为继承 BoundPropertyBean 特征

  遗憾的是 我还没有完全实现 Person 类现在支持接收 移除和通知监听器 但 Scala 为 firstName 成员生成的默认方法并没有利用它们 同样遗憾的是 这样编写的 Scala 没有很好的注释以自动地 生成利用 PropertyChangeSupport 实例的 get/set 方法 因此我必须自行编写 如清单 所示

  清单 Scala 的 Person POJO 第 种形式

  

  //This is Scala class Person(var firstName:String var lastName:String var age:Int) extends Object with BoundPropertyBean def setFirstName(newvalue:String) = val oldvalue = firstName firstName = newvalue firePropertyChange( firstName oldvalue newvalue) def setLastName(newvalue:String) = val oldvalue = lastName lastName = newvalue firePropertyChange( lastName oldvalue newvalue) def setAge(newvalue:Int) = val oldvalue = age age = newvalue firePropertyChange( age oldvalue newvalue) override def toString = [Person: firstName= + firstName + lastName= + lastName + age= + age + ]

  应该具备的出色特征

  特征不是一种函数编程 概念 而是十多年来反思对象编程的结果 实际上 您很有可能正在简单的 Scala 程序中使用以下特征 只是没有意识到而已

  清单 再见 糟糕的 main()!

  

  //This is Scala object App extends Application val p = new Person( Jennifer Aloi ) p addPropertyChangeListener(PCL) p setFirstName( Jenni ) p setAge( ) System out println(p)

  Application 特征定义了一直都是手动定义的 main() 的方法 实际上 它包含一个有用的小工具 计时器 如果系统属性 scala time 传递给了 Application 实现代码 它将为应用程序的执行计时 如清单 所示

  清单 时间就是一切

   $ scala Dscala time AppBean changed its firstName from Jennifer to JenniBean changed its age from to [Person: firstName=Jenni lastName=Aloi age= ][total ms]

  JVM 中的特征

  在这个时候 有必要提出这样一个问题 这种看似魔术的接口与方法结构(即 特征)是如何映射到 JVM 的 在清单 中 我们的好朋友 javap 展示了魔术背后发生了什么

  清单 Person 内幕

   $ javap classpath C:\\Prg\\scala final\\lib\\scala library jar;classes PersonCompiled from Person scala public class Person extends java lang Object implements BoundPropertyBean scala ScalaObject    public Person(java lang String java lang String int);    public java lang String toString();    public void setAge(int);    public void setLastName(java lang String);    public void setFirstName(java lang String);    public void age_$eq(int);    public int age();    public void lastName_$eq(java lang String);    public java lang String lastName();    public void firstName_$eq(java lang String);    public java lang String firstName();    public int $tag();    public void firePropertyChange(java lang String java lang Object java lang Object);    public void removePropertyChangeListener(java beans PropertyChangeListener);    public void addPropertyChangeListener(java beans PropertyChangeListener);    public final void pcs_$eq(java beans PropertyChangeSupport);    public final java beans PropertyChangeSupport pcs();

  请注意 Person 的类声明 该 POJO 实现了一个名为 BoundPropertyBean 的接口 这就是特征作为接口映射到 JVM 本身的方法 但特征方法的实现又是什么样的呢?请记住 编译器可以容纳所有技巧 只要最终结果符合 Scala 语言的语义含义即可 在这种情况下 它会将特征中定义的方法实现和字段声明纳入实现特征的类 Person 中 使用 private 运行 javap 会使这更加显著 — 如果 javap 输出的最后两行体现的还不够明显(引用特征中定义的 pcs 值)

  清单 Person 内幕 第 种形式

   $ javap private classpath C:\\Prg\\scala final\\lib\\scala library jar;classes PersonCompiled from Person scala public class Person extends java lang Object implements BoundPropertyBean scala ScalaObject    private final java beans PropertyChangeSupport pcs;    private int age;    private java lang String lastName;    private java lang String firstName;    public Person(java lang String java lang String int);    public java lang String toString();    public void setAge(int);    public void setLastName(java lang String);    public void setFirstName(java lang String);    public void age_$eq(int);    public int age();    public void lastName_$eq(java lang String);    public java lang String lastName();    public void firstName_$eq(java lang String);    public java lang String firstName();    public int $tag();    public void firePropertyChange(java lang String java lang Object java lang Object);    public void removePropertyChangeListener(java beans PropertyChangeListener);    public void addPropertyChangeListener(java beans PropertyChangeListener);    public final void pcs_$eq(java beans PropertyChangeSupport);    public final java beans PropertyChangeSupport pcs();

  实际上 这个解释也回答了为何可以推迟特征方法的执行 直至用该检查的时候 因为在类实现特征的方法之前 它实际上并不是任何类的一 部分 因此编译器可将方法的某些逻辑方面留到以后再处理 这非常有用 因为它允许特征在不了解实现特征的实际基类将是什么的情况下调用 super()

  关于特征的备注

  在 BoundPropertyBean 中 我在 PropertyChangeSupport 实例的构建中使用了特征功能 其构造方法需要属性得到通知的 bean 在早先定义的特征中 我传入了 this 由于在 Person 上实现之前并不会真正定义特征 this 将引用 Person 实例 而不是 BoundPropertyBean 特征本身 特征的这个具体方面 — 定义的推迟解析 — 非常微妙 但对于此类的 迟绑定 来说可能非常强大

  对于 Application 特征的情况 有两部分很有魔力 Application 特征的 main() 方法为 Java 应用程序提供普适入口点 还会检查 Dscala time 系统属性 查看是否应该跟踪执行时间 但由于 Application 是一个特征 方法实际上会在子类上出现(App) 要执行此方法 必须创建 App 单体 也就是说构造 App 的一个实例 处理 类的主体 这将有效地执行应用程序 只有在这种处理完成之后 特征的 main() 才会被调用并显示执行所耗费的时间

  虽然有些落后 但它仍然有效 尽管应用程序无权访问任何传入 main() 的命令行参数 它还表明特征的行为如何 下放到 实现类

  特征和集合

  在将具体行为与抽象声明相结合以便为实现者提供便捷时 特征非常强大 例如 考虑经典的 Java 集合接口/类 List 和 ArrayList List 接口保证此集合的内容能够按照插入时的次序被遍历 用更正规的术语来说 位置语义得到了保证

  ArrayList 是 List 的具体类型 在分配好的数组中存储内容 而 LinkedList 使用的是链表实现 ArrayList 更适合列表内容的随机访问 而 LinkedList 更适合在除了列表末尾以外的位置进行插入和删除操作 无论如何 这两种类之间存在大量相同的行为 它们继承了公共基类 AbstractList

  如果 Java 编程支持特征 它们应已成为出色的结构 能够解决 可重用行为 而无需诉诸于继承公共基类 之类的问题 特征可以作为 C++ 私有继承 机制 避免出现新 List 子类型是否应直接实现 List(还有可能忘记实现 RandomAccess 接口)或者扩展基类 AbstractList 的迷惑 这有时在 C++ 中称为 混合 与 Ruby 的混合(或后文中探讨的 Scala 混合)有所不同

  在 Scala 文档集中 经典的示例就是 Ordered 特征 它定义了名字很有趣的方法 以提供比较(以及排序)功能 如清单 所示

  清单 顺序 顺序

   //This is Scalatrait Ordered[A]   def pare(that: A): Int    def <  (that: A): Boolean = (this pare that) <    def >  (that: A): Boolean = (this pare that) >    def <= (that: A): Boolean = (this pare that) <=   def >= (that: A): Boolean = (this pare that) >=   def pareTo(that: A): Int = pare(that)

  在这里 Ordered 特征(具有参数化类型 采用 Java 泛型方式)定义了一个抽象方法 pare 它应获得一个 A 作为参数 并需要在 小于 的情况下返回小于 的值 在 大于 的情况下返回大于 的值 在相等的情况下返回 然后它继续使用 pare() 方法和更加熟悉的 pareTo() 方法(java util Comparable 接口也使用该方法)定义关系运算符(< 和 > 等)

  Scala 和 Java 兼容性

  实际上 伪实现继承并不是 Scala 内特征的最常见应用或最强大用法 与此不同 特征在 Scala 内作为 Java 接口的基本替代项 希望使用 Scala 的 Java 程序员也应熟悉特征 将其作为使用 Scala 的一种机制

  我在本系列的文章中一直强调 编译后的 Scala 代码并非总是能够保证 Java 语言的特色 例如 回忆一下 Scala 的 名字很有趣的方法 (例如 + 或 \\ ) 这些方法往往会使用 Java 语言语法中不直接可用的字符编码( $ 就是一个需要考虑的严重问题) 出于这方面的原因 创建 Java 可调用 的接口往往要求深入研究 Scala 代码

  这个特殊示例有些憋足 Scala 主义者 通常并不需要特征提供的间接层(假设我并未使用 名字很有趣的方法 ) 但概念在这里十分重要 在清单 中 我希望获得一个传统的 Java 风格工厂 生成 Student 实例 就像您经常在各种 Java 对象模型中可以看到的那样 最初 我需要一个兼容 Java 的接口 接合到 Student

  清单 我 学生

   //This is Scalatrait Student    def getFirstName : String;    def getLastName : String;    def setFirstName(fn : String) : Unit;    def setLastName(fn : String) : Unit;        def teach(subject : String)

  在编译时 它会转换成 POJI Plain Old Java Interface 查看 javap 会看到这样的内容

  清单 这是一个 POJI!

   $ javap StudentCompiled from Student scala public interface Student extends scala ScalaObject    public abstract void setLastName(java lang String);    public abstract void setFirstName(java lang String);    public abstract java lang String getLastName();    public abstract java lang String getFirstName();    public abstract void teach(java lang String);

  接下来 我需要一个类成为工厂本身 通常 在 Java 代码中 这应该是类上的一个静态方法(名称类似于 StudentFactory ) 但回忆一下 Scala 并没有此类的实例方法 我认为这就是我在这里希望得到的结论 因此 我创建了一个 StudentFactory 对象 将我的 Factory 方法放在那里

  清单 我构造 Students

  

  //This is Javaobject StudentFactory    class StudentImpl(var first:String var last:String var subject:String)        extends Student            def getFirstName : String = first        def setFirstName(fn: String) : Unit = first = fn        def getLastName : String = last        def setLastName(ln: String) : Unit = last = ln

  def teach(subject : String) =            System out println( I know + subject)   

  def getStudent(firstName: String lastName: String) : Student =            new StudentImpl(firstName lastName Scala )   

  嵌套类 StudentImpl 是 Student 特征的实现 因而提供了必需的 get()/set() 方法对 切记 尽管特征可以具有行为 但它根据 JVM 作为接口建模这一事实意味着尝试实例化特征将产生错误 —— 表明 Student 是抽象的

  当然 这个简单示例的目的在于编写出一个 Java 应用程序 使之可以利用这些由 Scala 创建的新对象

  清单 学生 Neo

   //This is Javapublic class App    public static void main(String[] args)            Student s = StudentFactory getStudent( Neo Anderson );        s teach( Kung fu );   

  运行此代码 您将看到 I know Kung fu (我知道 我们经过了漫长的设置过程 只是得到了一部廉价电影的推介)

  结束语

  特征提供了在 Scala 中分类和定义的强大机制 目的在于定义一种接口 供客户端使用 按照 传统 Java 接口的形式定义 同时提供一种机制 根据特征内定义的其他行为来继承行为 或许我们需要的是一种全新的继承术语 用于 描述特征和实现类之间的关系

cha138/Article/program/Java/hx/201311/26946

相关参考

知识大全 面向Java开发人员的Scala指南: Scala控制结构内部揭密

面向Java开发人员的Scala指南:Scala控制结构内部揭密  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起

知识大全 面向Java开发人员的Scala指南: 面向对象的函数编程

面向Java开发人员的Scala指南:面向对象的函数编程  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下

知识大全 面向Java开发人员的Scala指南: 实现继承

面向Java开发人员的Scala指南:实现继承  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  S

知识大全 面向Java开发人员的Scala指南: 增强Scitter库

面向Java开发人员的Scala指南:增强Scitter库  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一

知识大全 面向Java开发人员的Scala指南: 深入了解Scala并发性 了解 Scala 如何简化并发编

面向Java开发人员的Scala指南:深入了解Scala并发性了解Scala如何简化并发编  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后

知识大全 面向Java开发人员的Scala指南: 包和访问修饰符

面向Java开发人员的Scala指南:包和访问修饰符  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

知识大全 面向Java开发人员的Scala指南: 构建计算器,第1 部分

面向Java开发人员的Scala指南:构建计算器,第1部分  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一

知识大全 面向Java开发人员的Scala指南: 构建计算器,第 2 部分

面向Java开发人员的Scala指南:构建计算器,第2部分  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一

知识大全 面向Java开发人员的Scala指南: 深入了解Scala并发性 了解 actor 如何提供新的应

面向Java开发人员的Scala指南:深入了解Scala并发性了解actor如何提供新的应  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后

知识大全 Java开发者的Scala指南: Scala+Twitter=Scitter

Java开发者的Scala指南:Scala+Twitter=Scitter  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我