api中重载函数的原理_小心重载API方法

api中重载函数的原理

重载方法是API设计中的一个重要概念,尤其是当您的API是流利的API或DSL( 特定于域的语言 )时。

对于jOOQ就是这种情况,在这种情况下,您经常想使用与完全相同的方法名称来与库进行各种交互。






示例:jOOQ条件

package org.jooq;public interface Condition {// Various overloaded forms of the "AND" operation:Condition and(Condition other);Condition and(String sql);Condition and(String sql, Object... bindings);// [...]}

所有这些方法都使用“ AND”运算符将两个条件相互关联。 理想情况下,实现相互依赖,从而造成单点故障。 这会使事情变干 :

package org.jooq.impl;abstract class AbstractCondition implements Condition {// The single point of failure@Overridepublic final Condition and(Condition other) {return new CombinedCondition(Operator.AND, Arrays.asList(this, other));}// "Convenience methods" delegating to the other one@Overridepublic final Condition and(String sql) {return and(condition(sql));}@Overridepublic final Condition and(String sql, Object... bindings) {return and(condition(sql, bindings));}}

泛型和重载的麻烦

当使用Eclipse开发时,Java 5世界似乎比实际情况更加光彩照人。 Varargs和泛型在Java 5中作为语法糖引入。它们在JVM中并不是真的存在。 这意味着编译器必须正确链接方法调用,在需要时推断类型,并在某些情况下创建综合方法。 根据JLS( Java语言规范 ),当在重载方法中使用varargs / generics时,存在很多歧义。

让我们详细介绍一下泛型:

在jOOQ中要做的一件好事是将常量值与字段一样对待。 在许多地方,字段参数像这样重载:

// This is a convenience method:public static <T> Field<T> myFunction(Field<T> field, T value) {return myFunction(field, val(value));}// It's equivalent to this one.public static <T> Field<T> myFunction(Field<T> field, Field<T> value) {return MyFunction<T>(field, value);}

在大多数情况下,上面的方法效果很好。 您可以像这样使用上述API:

Field<Integer> field1  = //...Field<String>  field2  = //...Field<Integer> result1 = myFunction(field1, 1);Field<String>  result2 = myFunction(field2, "abc");

但是,当<T>绑定到对象时,就会出现麻烦!

// While this works...Field<Object>  field3  = //...Field<Object>  result3 = myFunction(field3, new Object());// ... this doesn't!Field<Object>  field4  = //...Field<Object>  result4 = myFunction(field4, field4);Field<Object>  result4 = myFunction(field4, (Field) field4);Field<Object>  result4 = myFunction(field4, (Field<Object>) field4);

当<T>绑定到Object时,两种方法突然都适用,并且根据JLS,它们都不是更具体的! 尽管Eclipse编译器通常比较宽容(并且在这种情况下直观地链接了第二个方法),但是javac编译器不知道该调用要做什么。 而且没有办法解决。 您不能将field4强制转换为Field或Field <Object>强制链接器链接至第二种方法。 对于API设计人员来说,这是个坏消息。

有关此特殊情况的更多详细信息,请考虑以下堆栈溢出问题,我将此问题报告给Oracle和Eclipse。 让我们看看哪种编译器实现是正确的:
http://stackoverflow.com/questions/5361513/reference-is-ambiguous-with-generics

静态导入的麻烦,varargs

Varargs是Java 5中引入的另一个重要功能。尽管它只是语法糖,但在将数组传递给方法时可以节省很多代码:

// Method declarations with or without varargspublic static String concat1(int[] values);public static String concat2(int... values);// The above methods are actually the same.String s1 = concat1(new int[] { 1, 2, 3 });String s2 = concat2(new int[] { 1, 2, 3 });// Only, concat2 can also be called like this, convenientlyString s3 = concat2(1, 2, 3);

那是众所周知的。 它与原始类型数组的工作方式与与Object []相同。 它也可以与T []一起使用,其中T是泛型类型!

// You can now have a generic type in your varargs parameter:public static <T> T[] array(T... values);// The above can be called "type-safely" (with auto-boxing):Integer[] ints   = array(1, 2, 3);String[] strings = array("1", "2", "3");// Since Object could also be inferred for T, you can even do this:Object[] applesAndOranges = array(1, "2", 3.0);

最后一个例子实际上已经暗示了这个问题。 如果T没有任何上限,则类型安全性完全消失。 这是一种错觉,因为最后,总是可以将varargs参数推断为“ Object…”。 这就是当您重载此类API时这会引起麻烦的方式。

// Overloaded for "convenience". Let's ignore the compiler warning// caused when calling the second methodpublic static <T> Field<T> myFunction(T... params);public static <T> Field<T> myFunction(Field<T>... params);

起初,这看起来是个好主意。 参数列表可以是常量值(T…)或动态字段(Field…)。 因此,原则上,您可以执行以下操作:

// The outer function can infer Integer for <T> from the inner// functions, which can infer Integer for <T> from T...Field<Integer> f1 = myFunction(myFunction(1), myFunction(2, 3));// But beware, this will compile too!Field<?> f2 = myFunction(myFunction(1), myFunction(2.0, 3.0));

内部函数将推断<T>的Integer和Double。 对于不兼容的返回类型Field <Integer>和Field <Double>,带有“ Field <T>…”参数的“打算”方法不再适用。 因此,编译器将带有“ T…”的方法一链接为唯一适用的方法。 但是您不会猜测<T>的(可能)推断范围。 这些是可能的推断类型:

// This one, you can always do:Field<?> f2 = myFunction(myFunction(1), myFunction(2.0, 3.0));// But these ones show what you're actually about to doField<? extends Field<?>>                       f3 = // ...Field<? extends Field<? extends Number>>        f4 = // ...Field<? extends Field<? extends Comparable<?>>> f5 = // ...Field<? extends Field<? extends Serializable>>  f6 = // ...

编译器可以推断出诸如Field <? 将Number&Comparable <?>和Serializable>扩展为<T>的有效上限。 但是,<T>没有有效的确切界限。 因此,必要的<? 扩展[上限]>。

结论

将varargs参数与泛型结合使用时要特别小心,尤其是在重载方法中。 如果用户将通用类型参数正确绑定到您想要的目标,则一切正常。 但是,如果有一个拼写错误(例如,将Integer与Double混淆),那么您的API用户就注定了。 而且他们不会轻易发现自己的错误,因为没有人能读懂这样的编译器错误消息:

Test.java:58: incompatible types
found   : Test.Field<Test.Field<? extends java.lang.Number&java.lang.Comparable<? extends java.lang.Number&java.lang.Comparable<?>>>>
required: Test.Field<java.lang.Integer>Field<Integer> f2 = myFunction(myFunction(1),myFunction(2.0, 3.0));

参考:在JAVA,SQL和JOOQ博客上,我们的JCG合作伙伴 Lukas Eder 谨慎使用了重载API方法 。

相关文章 :

  • Java中的数据库架构导航
  • ORM问题
  • Java泛型快速教程
  • 使用Spring和Java泛型简化数据访问层

翻译自: https://www.javacodegeeks.com/2011/12/overload-api-methods-with-care.html

api中重载函数的原理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/358068.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自动计算高度的方法 iOS, height为0, 可以自动计算weith,

height为0, 可以自动计算weith; weith为0, 可以自动计算height, 两者不可以同时为0 NSDictionary *dic {NSFontAttributeName: [UIFont systemFontOfSize:17]}; CGRect rect [joke.content boundingRectWithSize:CGSizeMake(375 - 20, 0) options:(NSStringDrawingUsesFontLe…

Fastjson 1.2.22-24 反序列化漏洞分析

Fastjson 1.2.22-24 FastJson在 1.2.22 - 1.2.24 版本中存在反序列化漏洞&#xff0c;主要原因FastJson支持的两个特性&#xff1a; fastjson反序列化时&#xff0c;JSON字符串中的 type 字段&#xff0c;用来表明指定反序列化的目标恶意对象类。 fastjson反序列化时&#xf…

new操作符具体都干了什么?一次笔试题遇到的

背景&#xff1a;一个笔试题简答谈到new操作符都干了什么&#xff1f;连续两次遇到&#xff0c;总结一下&#xff0c;不然不会的还是不会 new 共经过了4个阶段:1.创建一个空对象 let obj new Object();2.链接到原型 把 obj 的proto 指向构造函数Func的原型对象 prototype&am…

检测到堆栈粉碎

我敢打赌&#xff0c;每一个Java开发人员在他们的职业生涯初期都首次在Java代码中遇到本机方法时都会感到惊讶。 我还可以肯定&#xff0c;多年来随着了解JVM如何通过JNI处理对本机实现的调用而使惊喜消失了。 这篇文章是关于本机方法的最新经验。 更详细地讲&#xff0c;使用…

关于mysql中外键关联的一些个人理解

在我看来hibernate最麻烦的一件事就是配置外键关联&#xff0c;稍微不慎就会出现配置错误的情况&#xff0c;现在的项目全部都是在使用mybaits&#xff0c;而mybaits使用就简单的多&#xff0c;起码虽然说是要自己写mysql语句&#xff0c;但是起码这种做法在现阶段的项目开发中…

fastjson反序列化分析

1.fastjson简单使用 User: package com.naihe;public class User {private String name;private int age;public User() {}public User(String name, int age) {this.name name;this.age age;}public String getName() {return name;}public void setName(String name) {th…

防抖函数的实现

防抖函数的定义是当事件触发完成之后再延迟触发&#xff0c;并且只触发一次&#xff1b;如果在触发完成之前再次触发&#xff0c;则会再次刷新延迟&#xff1b;简单理解为&#xff08;如果事件不触发即不执行&#xff0c;并且只会执行一次&#xff0c;就是定时器最后走的那一次…

银行家算法:解决多线程死锁问题

死锁&#xff1a; 死锁产生的现场&#xff1a;当A进程P S2信号量而B进程P S1信号量时就会产生死锁&#xff0c;因为S2信号量需要B进程释放&#xff0c;而S1信号量需要A进程释放&#xff0c;因此两个进程都在等相互的资源&#xff0c;造成死锁。 死锁产生的条件&#xff1a; 互斥…

节流函数的实现,一次面试题遇到的编程题

在日常开发中有很多场景我们都需要用到节流函数和防抖函数&#xff0c;比如&#xff1a;实现输入框的模糊查询因为需要轮询ajax&#xff0c;影响浏览器性能&#xff0c;所以需要用到节流函数&#xff1b;实现手机号、姓名之类的的验证&#xff0c;往往我们只需要验证一次&#…

guice注入带参构造器_带有Guice的富域模型

guice注入带参构造器贫血域模型是一个非常常见的反模式。 在ORM和DI框架的世界中&#xff0c;我们自然会发现自己拥有一个由ORM管理的“域”&#xff0c;该域包含所有数据且无行为。 通过我们的DI框架有帮助地注入了辅助类&#xff0c;这些辅助类都是行为且没有数据。 在本文中…

转:巧用搜狗输入法输入英文单词

转&#xff1a; http://www.techweb.com.cn/digi/experience/2013-06-03/1300700.shtml 你是否遇到过这样的情形&#xff1a;想打一个英文单词&#xff0c;但是忘了具体拼写是什么&#xff0c;只是记了个大概?比如“竞争”&#xff0c;到底是competetion还是competition呢?又…

服务器ping不通的解决办法之阿里云云服务器VNC报错Failed to execute /sbin/init

背景:最近买了一个阿里云的云服务器,今天想安装阿里云的操作文档搭建一个博客网站来着,发现服务器公网IP都ping不通 解决办法参考: 方法一:如何解决ping请求超时的问题 方法二:本地ping服务器连接不到,总是超时 我的防火墙已经关闭,内网切换移动网络也不行,安全组…

从ofcms的模板注入漏洞(CVE-2019-9614)浅析SSTI漏洞(freemarker模板)

https://www.cnvd.org.cn/flaw/show/CNVD-2019-08488 思路: 1、pom.xml的时候发现存在模版引擎freemarker http://t.zoukankan.com/Eleven-Liu-p-12747908.html 2、寻找修改模版的地方 TemplateController.java 3、添加执行Payload <#assign ex“freemarker.template.utilit…

集合中的可选

有时有人认为Optional类型值得在集合中使用。 据称&#xff0c;它解决了以下问题&#xff1a; HashMap在没有键映射以及值null映射到键的情况下返回null 。 如果使用Map<Optional<Something>>则可以清楚地区分缺少的映射和缺少的值。 这样一来&#xff0c;您在兔子…

当你不知道今天星期几,不妨在编辑器写下这段代码

背景:最近加班比较严重,天天废寝忘食的写代码,不知春夏,看看今天星期几啦,实现方式很多,下面演示一下switch的方式 html: <!DOCTYPE html> <html><head><meta charset="utf-8"><title>孙叫兽测试switch语句</title></…

05.html学习-表单

表单标签&#xff1a; 表单标签的作用是用于提交数据给服务器的。 表单标签的根标签是<form>标签常用的属性&#xff1a; action: 该属性是用于指定提交数据的地址。 method&#xff1a; 指定表单的提交方式。 get : 默认使用的提交方式。 提交的数据会显示在地址栏上。 …

在Log4j2中更好地执行非日志记录器调用

使用Log4j 1.x并希望避免在某些情况下可能会造成额外的性能影响&#xff08;即使实际上未记录该消息&#xff09;时&#xff0c;通常使用日志记录防护 。 Java的简单日志记录外观 &#xff08; SLF4J &#xff09;带给Java日志记录的最吸引人的功能之一是能够减少需要进行这些日…

javaScript学习笔记之运算符

运算符 = 用于赋值。用于给 JavaScript 变量赋值。 运算符 + 用于加值。算术运算符 + 用于把值加起来。 下面展示了算术运算符及赋值运算符: <!DOCTYPE html> <html><head><meta charset="utf-8" /><title>孙叫兽测试运算符</…

编写高质量代码-OC 第7章 设计模式与Cocoa编程

45、设计模式是特定环境下的特定问题的解决方案46、MVC模式是一种复合或聚合模式47、对象建模在数据库中也广泛使用48、类簇可简化框架的公开架构而又不减少功能的丰富性 1、类簇基于抽象工厂设计模式2、类簇&#xff0c;可以用于隐藏实现的详细细节&#xff0c;为调用者提供一…

Goby反制复现

0x00 前言 最近复现Goby反制的时候遇到很多坑&#xff0c;记录一下反制过程以及遇到的坑点&#xff0c;还有世界上最强的黑客mux1ng帮我解决了很多问题。 0x01环境 攻击机&#xff1a; windows10 Goby1.8.230 172.20.10.3反制机&#xff1a; Windows7 Phpstudy2016 172.20.…