Scala中有一个概念,叫做“视界”。所谓“视界”是指,我不care这个对象具体是什么类型,但我可以把它“视作”某种类型加以利用。
比如说,有如下的函数定义:
def quick[T <% Ordered[T]](list: List[T]): List[T] = {
list match {
case Nil => Nil
case x::xs =>
val (before,after) = xs partition (_ < x)
quick(before) ++ (x :: quick(after))
}
}
OK,这是我从别的地方抄来的快速排序算法实现。重点不在算法这里。在“<%”这个符号上。这个符号说明了,对于T这个类型,只要符合与Ordered[T]的调用方式,甚至可以不是Ordered[T]的子类,都可以放到这个函数中使用。举例来说:
trait Ordered[T] {
def < (x: T): Boolean
}
Ordered特质定义了“<”这个函数。而Int类也定义了相同签名的函数,只是Int类并不继承于Ordered特质(这里继承的说法可能欠妥,Java习惯性思维,见谅)。因此,前面的快速排序使用了“<%”符号说明,只要能把对象“视作”某种类型,就可以用这个函数来排序。
那么,Java中是否可以用同样的思想做些什么事情呢?举例如下:
我们知道,连接数据库有三种常见对象,分别是Connection,Statement,以及ResultSet。这三种对象都有关闭方法,且签名一致。
public interface Connection {
//...
/**
* @exception SQLException if a database access error occurs
*/
void close() throws SQLException;
//...
}
public interface ResultSet {
//...
/**
* @exception SQLException if a database access error occurs
*/
void close() throws SQLException;
//...
}
public interface Statement {
//...
/**
* @exception SQLException if a database access error occurs
*/
void close() throws SQLException;
//...
}
为了聚集问题,摘抄的是JDK1.5的代码,因此可能与你看到的源代码不尽一致。
我们可以发现,三个对象源于三个接口,虽然方法签名一致,但接口不一样,因此无法作为同一类对象发给释放资源的函数。从而为了安全地释放三个对象,你需要这样写代码:
private void recycle(Connection conn, Statement stmt, ResultSet rs)
{
if (rs != null) {
try {
rs.close();
} catch (SQLException ex) {
// no-op
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException ex) {
// no-op
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException ex) {
// no-op
}
}
}
一般来讲,应该是这个样子的吧?每个对象的SQLException都必须单独catch住,并且什么都不做,然后执行下一个对象的释放。当然这里做的有点儿绝对,你可以考虑仅释放conn即可,我只是拿来做例子。
这里我们看到的是,三个对象的接口类型都包含了public void close() throws SQLException;方法,但它们不是同一个类型的对象。那么有什么办法把它们“视作”同一个对象吗?
以下的作法是错误的。
interface Resource
{
void close() throws SQLException;
}
//...
private void close(Resource res)
{
if (res != null) {
try {
res.close();
} catch (SQLException ex) {
// no-op
}
}
}
private void recycle(Connection conn, Statement stmt, ResultSet rs)
{
close((Resource) rs);
close((Resource) stmt);
close((Resource) conn);
}
//...
因为对象不能被造型为非父类或父接口的类型。
不过以上的方法启发了我们,我们需要的就是类似于“视界”效果的一种操作,或者说是辅助方法。因为Java内部没有建立“%>”机制,所以我们需要自己做。
以下是使用Java的Proxy实现的辅助方法,可以把任何对象造型为另一种类型的对象。不过造型之前会首先检查是否合法。目前仅检查函数名与参数列表,若细致一些还可以增加对访问修饰符和抛出异常的检查。
final class ViewBoundHelper
{
private ViewBoundHelper() { /* no-op */ }
private static final class Handler implements InvocationHandler
{
private final Object target;
public Handler(Object t)
{
target = t;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
return getDeclaredMethod(method).invoke(target, args);
}
Method getDeclaredMethod(Method m)
{
Class<?> cls = target.getClass();
while (true) {
try {
m = cls.getDeclaredMethod(m.getName(), m.getParameterTypes());
break;
} catch (NoSuchMethodException ex) {
cls = cls.getSuperclass();
if (cls == null) {
return null;
}
}
}
return m;
}
}
public static Object asIs(Object o, Class<?> intf)
{
Handler handler = new Handler(o);
for (Method method : intf.getDeclaredMethods()) {
if (handler.getDeclaredMethod(method) == null) {
throw new ClassCastException(o.getClass() + "can't be viewed as " + intf.getName());
}
}
return Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[] {
intf
}, handler);
}
}
使用方式如下:
public static void main(String[] args) throws SQLException
{
Connection conn = new FakeConn();
Resource res = (Resource) ViewBoundHelper.asIs(conn, Resource.class);
res.close();
System.out.println(res);
}
分享到:
相关推荐
读书笔记:用java模拟scala函数式编程模拟实现mapreduce
在Java项目中使用Scala,通常被称为Java和Scala的混编。这种混编允许开发团队在已有的Java项目中逐渐引入Scala代码,以利用其优势,同时保持与现有Java代码的兼容性。在实际应用中,可能会在服务端逻辑或者特定组件...
基于java、scala、python、spark实现的图书推荐系统源码+项目说明.zip基于java、scala、python、spark实现的图书推荐系统源码+项目说明.zip基于java、scala、python、spark实现的图书推荐系统源码+项目说明.zip基于...
在现代软件开发中,Java和Scala是两种广泛使用的编程语言。它们各有特色,Java以其稳定性和广泛的社区支持而著名,Scala则以其强大的函数式编程特性及对Java虚拟机(JVM)的无缝集成受到青睐。当一个项目中同时包含...
Master the fundamentals of Scala and understand its emphasis on functional programming that sets it apart from Java. This book will help you translate what you already know in Java to Scala to start ...
本资源提供了一套基于Java、Scala和Spark的数据处理与分析设计源码,包含1381个文件,其中包括634个CRC文件,316个BK文件,35个Class字节码文件,20个XML配置文件,15个Java源代码文件,13个JAR打包文件,8个...
《面向Java开发人员的Scala指南》是一本专为熟悉Java编程语言的开发者设计的书籍,旨在帮助他们理解和掌握Scala这门强大的多范式编程语言。Scala结合了面向对象和函数式编程的特点,提供了更高的代码抽象能力和性能...
标题中的“Scala Java相关开发工具”表明我们讨论的是与Java和Scala编程语言相关的开发环境和工具。Java和Scala都是在JVM(Java虚拟机)上运行的语言,它们有着紧密的联系,但各自拥有独特的特性和用途。 首先,...
本示例着重讲解如何在Java和Scala之间进行互调用,这是基于Maven构建系统的。Maven是Apache开发的项目管理工具,它可以帮助开发者管理项目的构建、依赖关系以及文档的生成。在Java和Scala的混合开发环境中,Maven...
该项目为Spark舆情模拟系统,采用Java语言作为主要开发语言,并融合Scala、JavaScript、Python、CSS和HTML等多种技术实现。整个项目包含75个文件,其中包括17个Java源文件、8个Scala源文件、7个JavaScript文件、6个...
模拟了1个WordCount.zip"表明这是一个使用Spring Boot框架构建的Spark应用程序,它结合了Java和Scala两种编程语言,旨在提供一个快速启动和运行的开发环境。其中,WordCount是经典的分布式计算案例,用于统计文本中...
Java 和 Scala 并发性基础
JAVA+Scala语言开发基于机器学习的商品类目预测源码+文档说明.zip本资源中的源码都是经过本地编译过可运行的,评审分达到95分以上。资源项目的难度比较适中,内容都是经过助教老师审定过的能够满足学习、使用需求,...
Scala到Java 用Scala编写的简单工具,揭示了Scala编译器的奥秘。 从StdIn读取scala代码,并将其反编译的Java版本写入StdOut。 用法 确保您已安装Java 1.8和Maven 检出项目 在项目目录中调用mvn clean package 。 ...
整个项目包含987个文件,具体分布如下:727个Java源文件,134个Scala源文件,54个XML文件,21个文本文件,17个属性文件,9个Markdown文件,5个Excel文件,3个备份文件,3个YAML文件,3个Protocol Buffers文件。...
Java电商大数据项目-推荐系统(java和scala语言) Bump spark.version from 2.1.0 to 2.4.7 in /MySparkProject dependencies #6 by dependabot bot was merged 4 minutes ago Bump junit from 3.8.1 to 4.13.1 in /...
功能:实现google的PageRank算法,带完整的测试数据和结果,java、scala语言版本 ********************************************************* 版本: scala2.10.4 spark 1.6.1 Scala IDE Build id: 4.4.1-vfinal...
该系统是一款基于Java和Scala语言开发的深圳地铁大数据客流分析系统源码,总计包含106个文件,其中包括40个Java源文件、20个Scala源文件、35个PNG图片文件、4个XML配置文件、1个7z压缩文件、1个gitignore文件、1个...
这个压缩包文件"Java中的函数式编程_Java_Scala_下载.zip"很可能包含了关于如何在Java中应用函数式编程思想以及对比Scala等其他函数式编程语言的资源。 函数式编程的核心特点包括: 1. **纯函数**:纯函数是指没有...
本项目是一款基于Java和Scala语言的陕西农林实训大数据课程资料与笔记下载平台源码,集成了65个文件,涵盖22个Scala源文件、15个PDF文档、8个Scala源文件、7个文本文件、2个Markdown文件、2个MP4视频、2个PNG图片、2...