根据维基百科,鸭子的打字是:

动态类型的类型,其中对象的方法和属性确定有效的语义,而不是其从特定类或特定接口的实现继承

用简单的话

当我看到一只鸟走路像鸭子,游泳像鸭子,嘎嘎像鸭子一样时,我称那只鸟为鸭子

在具有动态类型的语言中,此功能允许创建的功能不检查传递的对象的类型,而是依赖于其中存在的特定方法/属性,并在找不到这些属性时抛出运行时异常。 例如,在groovy中,我们可以使用一种方法来打印有关某个实体的信息

def printEntity = {entity ->println 'id: ${entity.id}, name: ${entity.name}'
}

假设我们有以下课程

class Entity {Long idString name
}

这样我们就可以调用我们的函数

printEntity(new Entity(id: 10L, name: 'MyName1'))
id: 10, name: MyName1

但是同时我们可以将map作为参数传递

printEntity(['id':10L, 'name':'MyName2'])
id: 10, name: MyName2

使用一些元编程魔术,我们甚至可以编写以下内容

class Ghost {def propertyMissing(String name) {if (name == 'id') {return -1L} else if (name == 'name') {return 'StubName'}}
}

而且我们仍然可以调用我们的函数

printEntity(new Ghost())
id: -1, name: StubName

欢迎来到真实的世界

幸运的是,这个概念不仅可以用于具有动态类型的语言,而且可以用于具有更严格类型模型的语言,例如Java。 Wikipedia很好地说明了使用Proxy类在Java中进行鸭子输入的实现。

好吧,你说,除了让自己成为最聪明的专家以外,这的实际用途是什么:)让我展示一些使用鸭子类型技术在Java中解决的现实生活任务。

从一开始,我就拥有一个简单的报表生成器,该报表生成器查询产品的数据库并输出某些实体的ID和名称。 但随后客户说:“我还想链接到我们网站上的实体详细信息页面。 美丽的SEO友好链接。 你能对我做吗? “当然”,我说。 深入研究我们的代码库后,我发现很酷的函数generateSeoUrl()可以完成这项工作。 该函数采用Entity类型的一个参数,即interface。 因此,我的目的是观察Entity的实现,并尝试使用其中之一进行报告生成。 当我发现它们全部都是某些自制的ORM工具的一部分并且他们的构造函数接受查询DB以获取有关产品的全部信息后,我感到非常惊讶。

因此,如果我使用的是Entity实现,则必须在报表的每一行中处理一个额外的查询,这是不可接受的,因为报表由大量的行组成。 因此,我决定尝试其他方法并实现Entity接口,该方法覆盖了generateSeoUrl()使用的方法。 我单击了IDE快捷方式,再次感到惊讶。 实体有大约50(!!!)个方法。 好吧,我已经知道generateSeoUrl()函数仅使用getEntityId()和getName(),但是再说一次,使用具有50个空方法的新类来覆盖其中的2个做有用的动作对我来说不是一个好主意。

因此,我决定停止尝试编码,并开始思考:)扩展某些Entity实现以防止查询数据库或复制+粘贴generateSeoUrl()并根据我的需要采用它,但是这些选择仍然很漂亮。 特别是当我提醒鸭子打字时。 我对自己说,我们有一个采用Entity实例但仅使用此接口的两种方法的函数,因此要完成我的任务,我需要看起来像Entity并能够处理getEntityId()和getName()方法的东西。

由于实体ID和名称已经存在于用于生成报告的数据中,因此我可以在新类中重用它们以对getEntityId()和getName()的数据进行存根。 为了实现鸭子类型,我们需要创建Proxy,该Proxy还实现InvocationHandler接口和静态方法来检索Proxy实例。 我班的最终代码看起来像

public class ReportEntitySupport implements InvocationHandler {public static Entity newInstance(Long entityId, String name) {return (Entity) Proxy.newProxyInstance(Product.class.getClassLoader(),Product.class.getInterfaces(),new ReportEntitySupport(entityId, name));}private final String name;private final Long entityId;private ReportEntitySupport(Long entityId, String name) {this.name = name;this.entityId = entityId;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (method.getName().equals('getName')) {return this.name;} else if (method.getName().equals('getEntityId')) {return this.entityId;}return null;}
}

那么如何使用呢?

在我的报表生成器类中,同时遍历ResultSet时,我正在使用以下代码

Long entityId;
String name;
....
Entity entity = ReportEntitySupport.newIntance(entityId, name);
String seoUrl = generateSeoUrl(entity);
....

聚苯乙烯

这篇文章仅说明了一些不常见的Java语言概念可以成功地用于完成现实生活中的任务,从而提高您的编程技能并使代码更漂亮。

参考: 鸭子在Java中打字? 嗯,这不完全是我们JCG合作伙伴 Evgeny Shepelyuk在jk的博客博客上获得的。

翻译自: https://www.javacodegeeks.com/2012/09/duck-typing-in-java-well-not-exactly.html

鸭子在Java中打字? 好吧,不完全是相关推荐

  1. 会java的鸭子_鸭子在Java中打字? 好吧,不完全是

    会java的鸭子 根据维基百科,鸭子的打字是: 动态类型的类型,其中对象的方法和属性确定有效的语义,而不是其从特定类或特定接口的实现继承 用简单的话 当我看到一只鸟走路像鸭子,游泳像鸭子,嘎嘎像鸭子一 ...

  2. java怎么实现手机投影,在Java中投射对象

    看看这个例子: public class A { //statements } public class B extends A { public void foo() { } } A a=new B ...

  3. java定义一个eat方法_小黄鸭系列java基础知识 | java中的方法

    前言 今天我们要探讨的问题,是java基础语法的最后一个问题,也就是java中的方法,今天主要从以下几个方面来介绍: 方法是什么(定义) 方法的分类 方法的调用 应该说,学完今天的知识,你至少应该看懂 ...

  4. java 鸭子类_Java中实现鸭子类型机制

    "当看到一只鸟走起来像鸭子.游泳起来像鸭子.叫起来也像鸭子,那么这只鸟就可以被称为鸭子."[引用维基] 一般而言,鸭子类型机制常见/用于动态语言,如Python.Ruby.JS.来 ...

  5. Java 中关于 try、catch、finally 中的细节分析

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:God Is Coder https://www.cnblo ...

  6. 面试季,Java中的static关键字解析

    点击上方"方志朋",选择"置顶或者星标" 你的关注意义重大! static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面 ...

  7. 深入探讨Java中的异常与错误处理

    Java中的异常处理机制已经比较成熟,我们的Java程序到处充满了异常的可能,如果对这些异常不做预先的处理,那么将来程序崩溃就无从调试,很难找到异常所在的位置.本文将探讨一下Java中异常与错误的处理 ...

  8. Java中的泛型 --- Java 编程思想

    前言 ​ 我一直都认为泛型是程序语言设计中一个非常基础,重要的概念,Java 中的泛型到底是怎么样的,为什么会有泛型,泛型怎么发展出来的.通透理解泛型是学好基础里面中非常重要的.于是,我对<Ja ...

  9. 深入Java中的位操作

    来源:https://0x9.me/I3YJk 引 学完本章节你将学会位的基础概念与语法,并且还会一些骚操作!! 与.或.非.位移 原码.反码.补码 字节.位.超区间...... 开始本章节之前,我们 ...

最新文章

  1. ipa包中图片进行了Compress之后的主要处理和作用
  2. php比较函数代码,php字符串比较函数
  3. C2872 “ACCESS_MASK”: 不明确的符号
  4. silverlight 调用默认打印机
  5. java判断是否安装了pdf_Java检查PDF文件是否损坏
  6. Halcon - 定位 - 卡尺
  7. 线程安全与可重入函数
  8. 第三次学JAVA再学不好就吃翔(part58)--String和StringBuffer分别作为参数传递
  9. MSP430F5529 DriverLib 库函数学习笔记(二)GPIO
  10. matlab aviobj,MATLAB AVI 视频读取处理
  11. P1319 压缩技术(python3实现)
  12. Appium 夜神 配置
  13. Javascript对象属性方法集锦
  14. JVM中的垃圾收集算法
  15. 详解 MySQL 基准测试和 sysbench 工具
  16. windows 自带计算器 calc 的使用
  17. windows命令行快速启动软件
  18. 【part1】Tensorflow Object detection API Win10使用教程(Anaconda、tensorflow object detection API安装)
  19. 【高等数学笔记】二元函数连续、可微、偏导数存在、偏导数连续、任意方向导数存在的关系
  20. 可解释深度学习:从感受野到深度学习的三大基本任务:图像分类,语义分割,目标检测,让你真正理解深度学习

热门文章

  1. redis-java客户端jedis测试
  2. centos上安装jdk
  3. junit4和junit5_JUnit5 TestSuite替代
  4. 普罗米修斯使用es数据库_用普罗米修斯和格拉法纳仪法来豪猪
  5. io.realm:rea_使Java具有响应性的框架和工具包:RxJava,Spring Reactor,Akka和Vert.x概述...
  6. Spring Security并发会话控制示例教程–如何限制Java JEE Web应用程序中的用户会话数...
  7. 阿帕奇跨域_阿帕奇光束
  8. svn: 没有演进历程信息_使用默认方法的接口演进–第二部分:接口
  9. tf/idf_Neo4j:带密码的TF / IDF(和变体)
  10. java 排序性能_Java8排序–性能陷阱