什么';这是Java中duck类型的一个例子吗?

什么';这是Java中duck类型的一个例子吗?,java,duck-typing,Java,Duck Typing,我最近刚刚听说了duck类型,我读了关于它的文章,但是我很难将示例翻译成Java,这对我的理解很有帮助 有谁能给出一个Java中duck类型的清晰示例,以及我可能如何使用它 : 如果使用接口,duck类型很简单,那么应该匹配方法名和返回类型。Java在设计上不适合duck类型。您可能选择的方式是反射: public void doSomething(Object obj) throws Exception { obj.getClass().getMethod("getName", ne

我最近刚刚听说了duck类型,我读了关于它的文章,但是我很难将示例翻译成Java,这对我的理解很有帮助

有谁能给出一个Java中duck类型的清晰示例,以及我可能如何使用它


如果使用接口,duck类型很简单,那么应该匹配方法名和返回类型。

Java在设计上不适合duck类型。您可能选择的方式是反射:

public void doSomething(Object obj) throws Exception {

    obj.getClass().getMethod("getName", new Class<?>[] {}).invoke(obj);
}

Java不实现duck类型。

Java中的类型是名义上的-兼容性基于名称。如果您需要有关duck类型(或结构类型)在Java中的外观的示例,请查看以下页面:该页面提供了用Whiteoak编写的程序示例:一种Java兼容语言,也支持结构类型。

通常,duck类型与动态类型语言一起使用。您将在运行时检查是否存在满足需要所需的方法或属性,而不管继承层次结构如何

除了使用反射(这会变得很难看)之外,最接近的方法是使用符合duck类型所需标准的最小接口。这很好地描述了这个概念。它失去了python、ruby或javascript中duck键入的简单性,但如果您希望获得高级别的可重用性,它在Java中实际上是相当好的做法。

请参阅。它非常详细地介绍了如何使用动态代理在Java中实现duck类型

总之:

  • 创建一个接口,该接口表示要通过duck类型使用的方法
  • 创建使用此接口的动态代理和通过反射调用底层对象上接口方法的实现对象(假设签名匹配)

使用java 8,您有两种方法:

注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);
}
静态接口动作{public int act();}
公共int forEachAct(列表操作列表){
int-total=0;
针对(行动a:行动列表)
总数+=a.行动();
}
公共无效示例(){
List actionList=新建ArrayList();
字符串example=“example”;
add(示例::length);
forEachAct(行动清单);
}
注意:2:使用匿名类(性能不是很好,但在一些非关键部分可以做到)

静态接口动作{
公共int法案();
公共字符串descripe();
}
公共无效示例(){
List actionList=新建ArrayList();
字符串example=“example”;
actionList.add(新操作(){
public int act(){return example.length();}
公共字符串descripe(){return“Action:+example;}
});
}
好定义:

对象是多态的,没有公共基类或接口的关联。


我编写了一个实用程序类来动态创建对象的装饰器。您可以将其用于duck键入:

例如:

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();
输出:

Quack!
Ribbip!
晚会迟到了(和往常一样),但我写了一个速成班,自己打字。看

它将只转到接口,但对于使用示例:

interface Bird {
    void fly();
}

interface Duck extends Bird {
    void quack();
}

class PseudoDuck {
    void fly() {
        System.out.println("Flying");
    }

    void quack() {
        System.out.println("Quacking");
    }
}

class Tester {
    @Test
    void testDuckTyping() {
        final Duck duck
                = DuckTyper.duckType(new PseudoDuck(), Duck.class);
    }
}

支持默认接口方法、参数,检查异常类型是否兼容,并将检查PseudoDuck类的所有方法(包括private)。但是还没有对通用接口进行任何测试。

应该注意的是,这并不是严格意义上的duck类型,但是使用动态代理(这就是它所做的)是Java所能得到的最接近的,我喜欢新的对象创建方法。如果你沿着Java反射路线走,会遇到一个名为“duckapter”的优雅库:我想知道,为什么用Java或任何静态类型语言实现duck类型很难或不可能?人们说使用界面我们可以。Plz解释。是的,但是这里的其他人可能没有读过那篇文章。这是一篇好文章-你认为你可以总结一下这里给出的解决方案,以防万一吗?添加了一个非常基本的解释。使用动态代理的Duck键入可以在更少的代码中实现--请参阅。只需注意,
代理实现的接口的顺序很重要:如果不正确,您将收到一个
java.lang.IllegalArgumentException:object不是声明类的实例。
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();
Quack!
Ribbip!
interface Bird {
    void fly();
}

interface Duck extends Bird {
    void quack();
}

class PseudoDuck {
    void fly() {
        System.out.println("Flying");
    }

    void quack() {
        System.out.println("Quacking");
    }
}

class Tester {
    @Test
    void testDuckTyping() {
        final Duck duck
                = DuckTyper.duckType(new PseudoDuck(), Duck.class);
    }
}