我刚刚听说过鸭子打字,我读了Wikipedia article关于它的问题,但是我很难将这些例子翻译成Java,这对我的理解非常有帮助。
是否有人能够提供Java中鸭子类型的明确示例以及我可能如何使用它?
答案 0 :(得分:43)
Java设计不适合鸭子打字。您可以选择这样做的方式是反思:
public void doSomething(Object obj) throws Exception {
obj.getClass().getMethod("getName", new Class<?>[] {}).invoke(obj);
}
但是我会提倡用动态语言来实现它,例如Groovy,它更有意义:
class Duck {
quack() { println "I am a Duck" }
}
class Frog {
quack() { println "I am a Frog" }
}
quackers = [ new Duck(), new Frog() ]
for (q in quackers) {
q.quack()
}
答案 1 :(得分:11)
见this blog post。它详细介绍了如何使用动态代理在Java中实现鸭子类型。
总结:
答案 2 :(得分:6)
interface MyInterface {
void foo();
int bar(int x, int y);
int baz(int x);
}
public class Delegate {
public int bar() {
return 42;
}
}
DuckPrxy duckProxy = new DuckPrxyImpl();
MyInterface prxy = duckProxy.makeProxy(MyInterface.class, new Delegate());
prxy.bar(2, 3); // Will return 42.
使用Dynamic Proxy对接口进行鸭子输入很简单,您应该匹配方法名称和返回类型。
答案 3 :(得分:5)
Java没有实现duck typing。
答案 4 :(得分:3)
使用java 8,您有两种方法:
nº1:如果您只需要一种方法,请使用lambdas
static interface Action { public int act(); }
public int forEachAct(List<Action> actionlist) {
int total = 0;
for (Action a : actionList)
total += a.act();
}
public void example() {
List<Action> actionList = new ArrayList<>();
String example = "example";
actionList.add(example::length);
forEachAct(actionList);
}
nº2:使用匿名类(性能不是很好,但在某些非关键部分可以完成)
static interface Action {
public int act();
public String describe();
}
public void example() {
List<Action> actionList = new ArrayList<>();
String example = "example";
actionList.add(new Action(){
public int act() { return example.length(); }
public String describe() { return "Action: " + example; }
});
}
答案 5 :(得分:1)
用Java命名是标称的 - 兼容性基于名称。如果你需要一个关于鸭子打字(或结构类型)在Java中的样子的例子,请看这个页面:http://whiteoak.sourceforge.net/#Examples它提供了用Whiteoak编写的程序的例子:一种兼容Java的语言,它也支持结构类型
答案 6 :(得分:1)
通常,duck typing与动态类型语言一起使用。无论继承层次结构如何,您都会在运行时检查是否存在满足您需求所需的方法或属性。
除了使用会变得难看的反射之外,你可以得到的最接近的是使用符合鸭子打字所需条件的最小接口。这个blog post很好地描述了这个概念。它失去了python或ruby或javascript中鸭子类型的简单性,但如果你正在寻找高水平的可重用性,它在Java中实际上是非常好的做法。
答案 7 :(得分:1)
答案 8 :(得分:1)
我编写了一个实用程序类来动态创建对象的装饰器。你可以用它来打鸭子: https://gist.github.com/stijnvanbael/5965616
示例:
fetchBatchSize
输出:
interface Quacking {
void quack();
}
class Duck {
public void quack() { System.out.println("Quack!"); }
}
class Frog {
public void quack() { System.out.println("Ribbip!"); }
}
Quacking duck = Extenter.extend(new Duck()).as(Quacking.class);
Quacking frog = Extenter.extend(new Frog()).as(Quacking.class);
duck.quack();
frog.quack();
答案 9 :(得分:1)
晚会(像往常一样),但我写了一个快速课程,自己做一些鸭子打字。请参阅here。
它只会转到接口,但是对于一个用法示例:
if ((Model.Version >= 1.2 && Model.Version <= 1.3) || Model.Locale == EnglishSpeaking)
{
...
}
else if ( Model.Version > 1.3 && Model.Locale == EnglishSpeaking )
{
...
}
else if ....
支持默认接口方法,参数,检查异常类型是兼容的,并将检查PseudoDuck类(包括私有)的所有方法。但是,还没有使用通用接口进行任何测试。