JAVA中使用通配符_java – 如何使用通配符迭代此通用列表?

欢迎来到

Double Dynamic Dispatch的世界.

AFAIK,你不能轻松地在Java上做.你可以做两种方式:quick’n’dirty,和访客方式:

Quick’n’dirty

您需要询问对象的类型,因此您需要在Fruit上使用一种清洗方法,该方法将根据其类型将调用重定向到正确的功能:

public void wash(Fruit f)

{

if(f instanceof Apple)

{

wash((Apple) f) ;

}

else if(f instanceof Peach)

{

wash((Peach) f) ;

}

else

{

// handle the error,usually through an exception

}

}

quick’n’dirty的问题是,编译器不会告诉你,目前没有洗涤方法处理的新的有效的Fruit(例如Orange).

游客

您可以使用访客模式进行结果:

public abstract class Fruit

{

// etc.

public abstract void accept(FruitVisitor v) ;

}

public class Apple extends Fruit

{

// etc.

public void accept(FruitVisitor v)

{

v.visit(this) ;

}

}

public class Peach extends Fruit

{

// etc.

public void accept(FruitVisitor v)

{

v.visit(this) ;

}

}

并将访问者定义为:

public interface class FruitVisitor

{

// etc.

// Note that there are no visit method for Fruit

// this is not an error

public void visit(Apple a) ;

public void visit(Peach p) ;

}

然后,您的洗衣机的访客:

public class FruitVisitorWasher : implements FruitVisitor

{

// etc.

// Note that there are no visit method for Fruit

// this is not an error

// Note,too,that you must provide a wash method in

// FruitVisitorWasher (or use an anonymous class,as

// in the example of the second edit to access the

// wash method of the outer class)

public void visit(Apple a)

{

wash(a) ;

}

public void visit(Peach p)

{

wash(p) ;

}

}

最后,你的代码可能是

FruitVisitorWasher fvw = new FruitVisitorWasher() ;

for( Fruit f: arguments)

{

f.accept(fvw) ;

}

Etvoilà…

访问者模式具有编译器会告诉您如果您添加了另一个水果(例如橙色)的优势,其中您编码了接受方法,并且忘记更新FruitVisitor模式以支持它.

然后,访客模式是可扩展的:您可以拥有一个FruitVisitorWasher,一个FruitVisitorEater,一个FruitVisitorWhatever,添加它们,而不需要修改Fruit,Apple,Peach等.

一个陷阱,但是,您必须手动写入每个Fruit类的accept方法(这是一个复制/粘贴操作),因为它是所有的工作“知道”正确的水果类型的方法.

编辑

如果你去找Quick’n’dirty解决方案,Samuel Parsonage的解决方案可能比我的更好:

这使得Java的反思(我是一个C编码器,所以反射不会成为一个自然的解决方案…我的坏…).我发现他的解决方案非常优雅,即使它闻到某种东西(所有的检查都将在运行时完成,所以你最好确保一切都OK …再次,通过C背景:如果有事情可以完成或错误可以在编译时检测到,在运行时移动应该尽可能避免)

编辑2

约翰·亚施普托特(John Assymptoth)评论说:

The Visitor pattern as you write it isn’t an option,since I can’t add the method wash to Fruit.

所以我会提供内联代码来证明wash()不会在Fruit里面工作.

(我将FruitVisitor从抽象类改为界面,这更好)

让我们想象一下,for循环在Foo类的bar方法里面,它有自己的洗涤方法:

public class Foo

{

public wash(Apple a) { /* etc. */ }

public wash(Peach p) { /* etc. */ }

public bar(List extends Fruit> arguments)

{

for( Fruit f: arguments)

{

wash(f) ; // we wand the right wash method called.

}

}

}

你想要正确的洗涤方法被调用,所以上面的代码将无法正常工作.

让我们重新使用FruitVisitor模式来纠正这个代码.我们将在bar方法中使用一个匿名类:

public class Foo

{

public void wash(Apple a) { System.out.println("Apple") ; }

public void wash(Peach p) { System.out.println("Peach") ; }

public void bar(List extends Fruit> arguments)

{

FruitVisitor fv = new FruitVisitor()

{

public void visit(Apple a)

{

wash(a) ; // will call the wash method

// of the outer class (Foo)

}

public void visit(Peach p)

{

wash(p) ; // will call the wash method

// of the outer class (Foo)

}

} ;

for(Fruit f: arguments)

{

f.accept(fv) ;

}

}

}

现在,它的作品,水果中没有洗涤方法.

请注意,此代码已针对1.6 JVM进行了测试,因此如果需要,我可以提供完整的代码.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值