当前位置: 首页 > 编程日记 > 正文

从 Java 到 Scala(二):object

本文由 Rhyme 发表在 ScalaCool 团队博客。

object是一种让静态回归常态、打破模式、天然的语言特性。

其实在写这篇文章之前,我思绪万千,迟迟不能落笔,总想着自己会不会遗漏了某个知识点,或者有讲得不太那么准确的地方,但是后来我想明白了,学习一样东西,最重要的并不是要了解它的每一个细节,而是要了解它的核心思想。如果你能够理解上面讲的那句话,我想你或许也就掌握了object

其实,object较之Java,更多的是一种思想设计理念上的升华,就如同我本来就该有这东西,你却需要我手动费很大地劲自己造出来一样。

object当中,我们可以轻松的构建出一个「单例对象」,而在Java当中我们通常得遵守一套「单例模式」的应用才能构建出一个单例对象。但是请你细想一番,「单例对象」难道不该是一种更加自然的存在吗?

另外,和「单例对象」一样,object当中的另一个重量级的语言特性:「伴生对象」也同样遵循这一套逻辑,让「静态」以一种更为常态的形式存在。

单例对象(Singleton Object)

// 构建一个单例对象Singleton
object Singleton {var hello = "Hello World"def sayHello:String = {hello}
}
复制代码

在Scala中,我们使用关键字object来构建单例对象。任何用到单例模式的地方,你都可以用Scala的object来实现。以下代码向你展示了在Scala中单例对象的基本使用。我们只需要在我们用到的地方引入我们需要的「单例对象」即可。

import Singleton._ //引入Singleton对象中的所有方法
class Test {def test:String = sayHello
}
复制代码

伴生对象(Companion Object)

在Java中,我们通常会用到既有实例方法又有静态方法的类,在Scala中我们可以通过「伴生类」和「伴生对象」来实现。刚开始,你可能会对这两个词感到困惑,其实不用慌张,你完全可以在一开始用Java中的普通的不包含静态的类来代替「伴生类」,用类中的所有的静态来代替「伴生对象」。说的简单一点,就是将Java类中的静态搬到一个单例对象中。

下面分别用Java和伴生对象来实现下面这个简单的售票功能。

使用Java实现的这段代码,这里就不再多说,我想你肯定比我还要熟悉。

public class TicketJava {private static int ticket = 10;private String name;public TicketJava(String name){this.name = name;}public static void sellTicketTo(String name){System.out.println(name + " get ticket " + ticket);}public void buyTicket() {sellTicketTo(name);}
}复制代码

以下是使用「伴生对象」实现的版本。你只需要关注一个细节,静态所在的位置

类同名且与类在同一个源文件下object对象就是「伴生对象」,与之相对的类就叫做「伴生类」。

伴生对象与静态实现的功能没有二异,原来静态所具备的特性,在「伴生对象」中都能找到。在Java中,静态特性包裹在Class类中,它们可以互访私有特性,因此你也就能明白接下来的这句话:「伴生对象」与「伴生类」能够互访私有特性

class Ticket(name: String) {// name 是类Ticket的成员变量// 在Scala中import语句可以写在任意地方// 因此你可以控制import语句的作用范围,使得代码更加灵活import Ticket._def buyTicket(): Unit = {// 调用伴生对象中的方法sellTicketTo(name)}
}
// 伴生对象,和类同名,且在同一个源文件下,可以互访私有属性
object Ticket {private var ticket: Int = 10def sellTicketTo(name: String): Unit = {println(f"$name get ticket $ticket")ticket = ticket - 1}
}
复制代码

扩展类或特质的对象

特质:可以理解为Java中的接口

在Scala中,所有用object修饰的都是「单例对象」,我们以后将用「单例对象」代替Scala中的对象这个概念。

关于单例对象,你需要记住一个核心的理念:共享。单例对象、单例模式,所有和单例相关的都离不开共享这个概念。或者说的更准确一点,是共享对象

对象在本质上可以具备类的所有特性,因为类是对象的模板,对象不过是类的一个实例而已。而类有一个重要的特性:继承或实现。在Scala中我们会将继承或实现称作扩展类或特质。扩展使得类能够进行更好的抽象。在Java中我们通常会对类执行扩展操作,但是在Scala中,自从单例对象被作为一种更常态的特性,单例对象也可以扩展类或特质来实现更多的功能。其中一个很典型的应用就是借助单例对象的扩展来表示一些公共的状态。

例如以下代码:

我们可以通过用「单例对象」继承指定的抽象结构来共享一些默认的状态和对象。其实,关键的核心思想还是两个字共享

abstract class Status(var status: Int) {def operation()
}object Ok extends Status(200) {override def operation(): Unit = println("Ok operation")
}object Error extends Status(500) {override def operation(): Unit = println("Error operation")
}复制代码

与此类似的,我们通过继承Enumeration接口可以在Scala中实现枚举的功能。Scala默认没有实现枚举功能的。具体的这里不进行讲述,感兴趣的可以上网进行查询。

总而言之,凡是有共享这个概念的地方,你都可以考虑使用「单例对象」来实现。

apply方法

首先来看一段代码

new Array[Person](new Person("Rhyme"),new Person("Captain"))
Array[Person](Person("Rhyme"),Person("Captain"))
复制代码

你觉得哪种形式更加简洁直观呢?第一种方式这里不再解释,第二种方式,你会发现,我们省去了new关键字。

我们先不管具体的语言特性,单从代码本身来看,你会更倾向于哪一种?

很明显,我会选择第二种省去new关键字的方式。原因很简单:更加自然,更加简洁。首先,作为同行,想必new关键字我们再熟悉不过了。敲了它不下一万遍有没有!敲了这么多,你就没有感觉过吗?

其实这个字很关键,一旦你写某段代码写得烦了,就说明这段代码本身就是存在题的。然而如果你觉得它并没有什么,那只能说明你已经麻木了,作为一个好的程序员,不应该麻木,我们要想法设法,写最关键的代码

首先作为一个全民公认的new操作,为什么我不可以将new这个关键字从类名前面移去呢?注意我们关注的应该是最关键的代码new关键字对我来说,已经是再熟悉不过的东西了,它对我已经没有价值了,就让他默认存在就好了,我不需要再看到它!

而这种可以帮你省去new操作的语言特性我们就可以使用apply方法来实现。

我们通常会在伴生对象中定义一个apply()方法,例如如下代码:

class Person(name: String) {
}object Person {def apply(name: String):Person = new Person(name)
}
复制代码

apply方法将为我们返回一个「伴生类」的对象。当我门在执行Person("Rhyme")的时候,默认就会调用「伴生对象」中的apply()放回,并为你返回一个创建好的对象。如果你不想使用apply()方法,自己定义一个更适合自己的工厂方法也是一个不错的选择。

class Person(name: String) {
}object Person {def createPerson(name:String):Person = {new Person(name)}
}
复制代码

回归常态

其实,以上这些特性,你发现没有,Scala在底层的技术实现上,并没有做太多的改变,将这些Scala代码编译,用javap来查看编译之后的代码,你会发现它利用的依然是原先Java中的那些代码逻辑,只不过它一直在做优化,一直在简化,让单例静态对象创建等语言特性回归它们应有的常态,让他们成为一种天然的语言特性存在着,就像鱼儿之于大海一样自然的存在着。

最后,再让我们回到最开始讲的那句话:object是一种让静态回归常态、打破模式、天然的语言特性。 仔细再品味品味,你是不是又有一些新的体会呢!

在下一篇中,我们会继续探索object更加具体的应用,比如如何去改造Java传统的工厂方法和模式。

相关文章:

Python获取屏幕分辨率大小

获取屏幕大小有两种方法可以办到: 1.wxPython里的 2.win32api 1 #coding:gb23122 #wxApp.py 3 #author: aoogur4 importos5 importwx6 fromwin32api importGetSystemMetrics7 8 classFrame(wx.Frame):9 def__init__(self):10 wx.Frame.__init__(self,None,-1,title"wxApp.…

安卓事件传递机制

1.触摸事件 MotionEvent ACTION_DOWN:按下 ACTION_MOVE:移动 ACTION_UP:松开 2.以上三个触摸事件都会经历三个函数 事件分发(Dispatch):dispatchTouchEvent 事件拦截 (Intercept):onInterceptTouchEvent 事…

财务软件的管理监督

随着现代企业的发展,企业财务管理的内涵、外延、功能及其地位发生了深刻的变化,强化企业的财务管理已经成为现代企业在激烈的市场竞争中得以生存和发展、现代企业制度得以保证和实施的重要环节。财务管理软件的应用已经非常普及了。 现代企业财务管…

[Vue CLI 3] 插件编写实战和源码分析

当你看过了官方的几个插件之后,慢慢地,其实你也有需求了。 那如何编写一个 Vue CLI 3 的插件呢?本文代码已经放到 github 上,地址:https://github.com/dailynodej... 我们建一个文件夹,取名 vue-cli-plugin…

突然想起99年的那次离别

今天妹妹离开成都回家了突然发现某一件事情又那么蹿了出来了,是99年的秋天那次,同f到成都且分开的那短暂的2天!很多年了,不知道是忘记了再回忆起,还是一直埋在最深处,瞬间又重现!想了&#xff0…

列表组件之ListView

1.ListView是什么 一个显示可滚动项目的视图组件系统使用Adapter(适配器)将列表项目插入列表适配器从来源提取内容 下图从MVC分析的话,ListView相当于View,Adapter相当于Controller,data相当于Model 缺点:屏幕里面只能展示有限个…

C#杂记系列之日期函数

//2008年4月24日 System.DateTime.Now.ToString("D"); //2008-4-24 System.DateTime.Now.ToString("d"); //2008年4月24日 16:30:15 System.DateTime.Now.ToString("F"); //2008年4月24日 16:30 System.DateTime.Now.ToString("f"); /…

对着电脑笑了二十分钟(2)

25、有一次我大叔见我小姑在搽大宝,突然大叫一声:“你皮肤这么好,还用护舒宝啊?”26、老师留下作业,我不会做就抄别人的,然后去办公室交作业,看见老师说:“我抄完了!”27…

ORACLE临时表空间

https://www.cnblogs.com/kerrycode/p/4006840.html转载于:https://www.cnblogs.com/elontian/p/9564296.html

列表组件之RecyclerView

灵活体现在 ListView 只支持上下滑动 RecyclerView 可以左右滑动,可以瀑布流 并且默认支持布局:线性布局、网络布局 RecyclerView将很多固定模式的地方抽象出来了,如用于动画的ItemAnimator和用于布局的LayoutManager Adapet的特点 1.ViewHo…

【WPF】一个简单的ColorPicker控件

在斯克迪亚看到一篇WPF动态改变主题颜色的文章,来了兴趣,于是自己搞了个简单的ColorPicker控件。 控件其实很简单,定义了5个依赖属性 FinalBrushProperty, AProperty, RProperty, GProperty, BProperty 然后当A,R,G,B发生变化时,…

javascript 利用 - 枚举思想 - 添加地名的一个小例子

利用枚举思想来添加地名&#xff0c;主要功能是&#xff1a;判断点击a标签&#xff08;即当前的地名&#xff09;如果在ul的li不存在的话那么就添加&#xff0c;有则不添加&#xff0c;而且还提供了相应的排序功能... HTML代码&#xff1a; <div id"china"> &l…

[MaxCompute MapReduce实践]通过简单瘦身,解决Dataworks 10M文件限制问题

用户在DataWorks上执行MapReduce作业的时候&#xff0c;文件大于10M的JAR和资源文件不能上传到Dataworks&#xff0c;导致无法使用调度去定期执行MapReduce作业。 解决方案&#xff1a; 第一步&#xff1a;大于10M的resources通过MaxCompute CLI客户端上传&#xff0c; 客户端下…

根据给定数据创建JSON并验证

首先可以判断&#xff0c;temp和weather的值是对象&#xff0c;success的值为布尔型&#xff0c;notification的值为一个数组 {"temp":{"min":11.34,"max":19.01},"weather":{"id":"801","condition":…

C# + MySql 存贮过程开发示例

MySql 发展至今&#xff0c;已经不是当初那个只依靠免费和速度取胜的开源数据库服务器了&#xff0c;它提供的一系列 GUI 工具&#xff0c;以及加入商业数据库的一些特性&#xff0c;依然免费并且开源&#xff0c;让我们实在无法拒绝它的魅力。 很多人在谈及 MySql 可能会条件反…

[C#]判断是否是合法的IP4,IP6地址

判断一个字符串如果没有端口的话&#xff0c;利用IPAddress.TryParse很好判断&#xff0c;那么有端口怎么判断呢&#xff0c;正则表达式&#xff1f;还是其他方式&#xff1f; 关键代码&#xff1a; /// <summary>/// 判断是否是合法的IP4,IP6地址/// </summary>//…

Centos 7使用vsftpd搭建FTP服务器

FTP&#xff0c;即&#xff1a;文件传输协议&#xff08;File Transfer Protocol&#xff09;&#xff0c;基于客户端/服务器模式&#xff0c;默认使用20、21端口号&#xff0c;其中端口20&#xff08;数据端口&#xff09;用于进行数据传输&#xff0c;端口21&#xff08;命令…

Android中的网络(字节跳动)

文章目录RESTful API对REST的解释资源与URI什么是URIHTTP URL的组成Http 接口JSONHttp资源XMLJSONAndroid中对JSON的处理方法一&#xff1a;org.json.JSONObject方法二&#xff1a;GSON(toJson,fromJson)RetrofitRESTful API 对REST的解释 REST描述的是在网络中客户端和服务端…

编写和调试Shader程序(1)

编写和调试Shader程序&#xff08;1&#xff09;DirectX EffectEditJohnsonFeng常用的Shader编写程序有ATI Render Monkey和NVIDIA FX Composer,另外还有DirectX自带的EffectEdit。这几款工具都比较容易上手&#xff0c;本文先介绍DirectX的EffectEdit。EffectEdit是DirectX9.0…

(24):(行为型模式) Visitor 访问者模式

[所有分类] 转载于:https://www.cnblogs.com/hyp5490-/p/3891411.html

二十二、新人成才之路《做人七项原则 做一个节俭惜福的人》

人的福报有先天福报和后天福报。先天福报是从出生时&#xff0c;就注定的。你是个有福的人&#xff0c; 还是个福气少的人。比如出身富贵之家的孩子&#xff0c;可能天生福报较大。出身贫穷人家的孩子&#xff0c; 天生福报可能就较小。也有贫苦孩子通过奋斗努力&#xff0c;最…

代码版本控制工具Concurrent Versions System(CVS)的三种用配置库更新本地工作目录文件的方法

(1)选中文件右键->team->update (2)选中文件右键->replace with->latest from HEAD (3)选中文件右键->team->synchronize with repository 注&#xff1a;第三种方法会以可视化的方式让用户对比本地工作目录和远程配置库中文件的区别 可以用当中的copy方法来…

SPOJ AMR10I Dividing Stones --DFS

题意&#xff1a;给n个石头&#xff0c;分成一些部分&#xff08;最多n部分&#xff0c;随便分&#xff09;&#xff0c;问分完后每部分的数量的乘积有多少种情况。 分析&#xff1a;可以看出&#xff0c;其实每个乘积都可以分解为素数的乘积&#xff0c;比如乘积为4&#xff0…

Cookie注入是怎样产生的

Cookie注入是怎样产生的 现在很多网站都加了防注入系统代码&#xff0c;你输入注入语句将无法注入~~感觉这样的防注入系统不错&#xff0c;但防注入系统没有注意到 Cookies 的问题&#xff01;所以就有了Cookies注入~~我们来研究一下怎样情况下才会有Cookies注入!如果你学过ASP…

阿里最强热修复:Sophix 超高速集成与踩坑

超高速集成 public class SophixStubApplication extends SophixApplication {private final String TAG "Sophix";// 此处SophixEntry应指定真正的Application&#xff0c;并且保证RealApplicationStub类名不被混淆。KeepSophixEntry(GowildApplication.class)stat…

安卓开发|自定义监听器的三个步骤

首先&#xff0c;要有一个实现View.OnClickListener接口的类这个类要重写onClick(View v)这个方法&#xff0c;里面加入想要触发的事件将监听器绑定在要监听的组件上&#xff0c;例如 holder.verticalLinear.setOnClickListener(MyAdapter.this);setOnClickListener的参数即为…

自己用C#写一个采集器、蜘蛛(zz)

效果图&#xff1a; 代码如下&#xff1a; usingSystem;usingSystem.Collections.Generic;usingSystem.Text;usingSystem.Net;usingSystem.Web;usingSystem.IO;usingSystem.Collections;usingSystem.Text.RegularExpressions;namespacechinaz { classProgram { …

DataPipeline |《Apache Kafka实战》作者胡夕:Apache Kafka监控与调优

胡夕&#xff0c;《Apache Kafka实战》作者&#xff0c;北航计算机硕士毕业&#xff0c;现任某互金公司计算平台总监&#xff0c;曾就职于IBM、搜狗、微博等公司。国内活跃的Kafka代码贡献者。 前言虽然目前Apache Kafka已经全面进化成一个流处理平台&#xff0c;但大多数的用户…

windows程序移植linux

1&#xff0c;路径名统一用正斜杠“/”。&#xff08;windows下正反斜杠都识别&#xff0c;linux只认正斜杠。&#xff09; 2&#xff0c;统一使用UTF-8格式编码。 vim中无法保存汉字时&#xff0c;可输入下列命令&#xff1a; &#xff1a;set fileencodingprc &#xff1a;se…

完美解决方案 | 完全卸载任何版本office残余文件

采用微软官方给的卸载文件&#xff0c;注意需要能够科学上网 然后再用拼夕夕的安装包重装就能装上&#xff0c;不会提示以下 折腾好久&#xff0c;这次亲测有效 参考文章