旧问题,但没有答案提供Java的具体解决方案,以一个干净的方式解决问题。

事实上,不容易但非常有趣的问题。这是我的贡献。

好的,要调用的方法是在编译时决定的。有没有解决方法来避免使用instanceof运算符?

正如优秀的@DaveFar回答中所述,Java仅支持单调度方法。

在这种调度模式下,编译器通过依赖声明的参数类型而不是它们的运行时类型来编译方法,以便在编译时立即调用。

我有一个集合(或列表或数组列表),我想在其中放置String值和double值。

为了以一种干净的方式解决问题并使用双重调度,我们必须为操纵数据带来抽象。

为什么?

这里有一个天真的访问者方法来说明问题:

public class DisplayVisitor {

void visit(Object o) {

System.out.println("object"));

}

void visit(Integer i) {

System.out.println("integer");

}

void visit(String s) {

System.out.println("string"));

}

}

现在,问题:访问类如何调用visit()方法?

双调度实现的第二次调度依赖于接受访问的类的“this”上下文。

所以我们需要在accept(),Integer和String类中使用Object方法来执行第二次调度:

public void accept(DisplayVisitor visitor){

visitor.visit(this);

}

但不可能!访问类是内置类:String,Integer,Object。

所以我们无法添加此方法。

无论如何,我们不想添加它。

因此,为了实现双分派,我们必须能够在第二个分派中修改我们想要作为参数传递的类。

因此,我们将操纵Object和List而不是操纵Foo和List,其中Foo类是包含用户值的包装器。

这是Foo界面:

public interface Foo {

void accept(DisplayVisitor v);

Object getValue();

}

getValue()返回用户值。

它将Object指定为返回类型,但Java支持协方差返回(从1.5版本开始),因此我们可以为每个子类定义更具体的类型以避免向下转换。

ObjectFoo

public class ObjectFoo implements Foo {

private Object value;

public ObjectFoo(Object value) {

this.value = value;

}

@Override

public void accept(DisplayVisitor v) {

v.visit(this);

}

@Override

public Object getValue() {

return value;

}

}

StringFoo

public class StringFoo implements Foo {

private String value;

public StringFoo(String string) {

this.value = string;

}

@Override

public void accept(DisplayVisitor v) {

v.visit(this);

}

@Override

public String getValue() {

return value;

}

}

IntegerFoo

public class IntegerFoo implements Foo {

private Integer value;

public IntegerFoo(Integer integer) {

this.value = integer;

}

@Override

public void accept(DisplayVisitor v) {

v.visit(this);

}

@Override

public Integer getValue() {

return value;

}

}

这是访问Foo子类的DisplayVisitor类:

public class DisplayVisitor {

void visit(ObjectFoo f) {

System.out.println("object=" + f.getValue());

}

void visit(IntegerFoo f) {

System.out.println("integer=" + f.getValue());

}

void visit(StringFoo f) {

System.out.println("string=" + f.getValue());

}

}

这是一个测试实现的示例代码:

public class OOP {

void test() {

List foos = Arrays.asList(new StringFoo("a String"),

new StringFoo("another String"),

new IntegerFoo(1),

new ObjectFoo(new AtomicInteger(100)));

DisplayVisitor visitor = new DisplayVisitor();

for (Foo foo : foos) {

foo.accept(visitor);

}

}

public static void main(String[] args) {

OOP oop = new OOP();

oop.test();

}

}

输出:

string =一个字符串

string =另一个String

整数= 1

对象= 100

改进实施

实际的实现需要为我们想要包装的每个buit-in类型引入一个特定的包装类。如上所述,我们无法选择双重调度。

但请注意,可以避免Foo子类中重复的代码:

private Integer value; // or String or Object

@Override

public Object getValue() {

return value;

}

我们确实可以引入一个包含用户值的抽象泛型类,并提供一个访问器:

public abstract class Foo {

private T value;

public Foo(T value) {

this.value = value;

}

public abstract void accept(DisplayVisitor v);

public T getValue() {

return value;

}

}

现在qazxsw poi子类更轻松地声明:

Foo

并且应修改public class IntegerFoo extends Foo {

public IntegerFoo(Integer integer) {

super(integer);

}

@Override

public void accept(DisplayVisitor v) {

v.visit(this);

}

}

public class StringFoo extends Foo {

public StringFoo(String string) {

super(string);

}

@Override

public void accept(DisplayVisitor v) {

v.visit(this);

}

}

public class ObjectFoo extends Foo {

public ObjectFoo(Object value) {

super(value);

}

@Override

public void accept(DisplayVisitor v) {

v.visit(this);

}

}方法以在test()声明中为?类型声明通配符类型(Foo)。

List

事实上,如果真的需要,我们可以通过引入java代码生成来简化进一步的void test() {

List> foos = Arrays.asList(new StringFoo("a String object"),

new StringFoo("anoter String object"),

new IntegerFoo(1),

new ObjectFoo(new AtomicInteger(100)));

DisplayVisitor visitor = new DisplayVisitor();

for (Foo> foo : foos) {

foo.accept(visitor);

}

}子类。

声明此子类:

Foo

可以像声明一个类并在其上添加注释一样简单:

public class StringFoo extends Foo {

public StringFoo(String string) {

super(string);

}

@Override

public void accept(DisplayVisitor v) {

v.visit(this);

}

}

其中@Foo(String.class)

public class StringFoo { }是在编译时处理的自定义注释。

java重载能否发生多次,java - 在Java中重载和多次调度 - SO中文参考 - www.soinside.com...相关推荐

  1. shell看java控制台_java - 为什么我的shell脚本的输出不能打印在控制台? - SO中文参考 - www.soinside.com...

    我试图用java在控制台打印一个shell脚本的输出.当我手动运行该脚本时,我得到C:/Users/user1/Desktop/shell.sh: line 78: /usr/ucb/ps: No s ...

  2. java zoneoffset,java - 如何在java8中获取默认的ZoneOffset? - SO中文参考 - www.soinside.com...

    tl;dr OffsetDateTime.now().getOffset() 但您可能应该使用时区而不是仅仅偏离UTC. ZoneId.systemDefault() Offset versus Ti ...

  3. Java点击按钮加一行数据_java - 单击按钮java时如何从txt文件绘制下一行? - SO中文参考 - www.soinside.com...

    单击按钮java时如何从txt文件绘制下一行? 问题描述 投票:0回答:1 import javax.swing.*; import java.awt.*; import java.awt.event ...

  4. java. tcp. 权限,java - tcpdump的不能够写PCAP文件。没有权限 - SO中文参考 - www.soinside.com...

    我开发我的Java应用程序,所以我可以在我的机器接口的数据包嗅探和转储结果滚动PCAP文件的网络监控解决方案.当从Java代码启动(使用sudo)tcpdump命令,我得到tcpdump: /path ...

  5. java saop 中文乱码_java - 使用Java进行SOAP服务调用时出错 - SO中文参考 - www.soinside.com...

    我有HTTPS Web服务.我可以使用wsimport生成Java类,但是在调用服务时收到以下异常:com.sun.xml.internal.ws.client.ClientTransportExce ...

  6. 初始化java工具失败,“初始化 Java 工具”期间发生了内部错误, java.lang.NullPointerException...

    今天刚打开eclipse就报了这个错误,我怀疑是昨晚想关电脑的时候,关闭eclipse太快,没有等待工作空间保存就关了电脑的缘故 错误如图: (图片来自下方链接博客,因为忘记截图了) 我百度后按照提示 ...

  7. 另一个.java文件调用_java - 如何调用另一个类“写文件”的方法? - SO中文参考 - www.soinside.com...

    在我的Android应用程序,我想有一类处理所有"写入/读取到文本文件"的行动.所以,我根本就调用我的readUserFile.java文件我想的方法.但我的方法将不会在该文件中工 ...

  8. java游戏移动_java - Java游戏 - 如何让敌人移动? - SO中文参考 - www.soinside.com

    Java游戏 - 如何让敌人移动? 问题描述 投票:1回答:2 我正在做一个射击游戏,并添加了许多带阵列的敌人,然后在地图上给他们一个随机位置,但我不知道如何让他们在到达他们的位置后移动.这是我的敌人 ...

  9. java方法未定义类型_java - 方法未定义为类 - SO中文参考 - www.soinside.com

    我试图在eclipse中运行一个使用名为getArea(一个对象)的方法的代码.我目前收到错误说 对于getArea(ComparableRectangle)类型,方法RectangleTest未定义 ...

最新文章

  1. .NET部分知识点整理
  2. 六:Cocos2d-x的CCLayer
  3. windows下配置java
  4. 深入理解 Python 中的上下文管理器
  5. c#中一个进程启动另一个进程并传递参数
  6. SQLyog 安装过程
  7. 使用maven工具无法进入debug
  8. 95-230-022-源码-WordCount走读-OperatorChain
  9. Android FloatingActionButton(FAB) 悬浮按钮
  10. 联通发送wap push备忘录
  11. 这37个自学网站,一年让你省下十几万。钱买辆车他不香嘛
  12. 二维图像中Mat::setp、Mat::step1理解
  13. Cross-lingual Document Retrieval using Regularized Wasserstein Distance
  14. 阅读替换净化规则_免费阅读APP-阅读下载 v3.2安卓版(免费小说阅读器纯净无广告)-KK下载站...
  15. JAVA实现模板word文档导入,Java依据word模板生成word文档之后台解析和实现及部分代码(一)...
  16. 计算机网络——移动IP
  17. 用C语言写学生成绩管理系统
  18. 友盟+林鸣晖:友盟+产品矩阵助力开发者全面提效
  19. 在哪个分区安装linux,partitioning - 如何找出Ubuntu安装在哪个分区上? - Ubuntu问答...
  20. 鸿蒙系统暗黑2,暗黑2 二十大最难爆出来的暗金装备(上)

热门文章

  1. 终端怎么进入hadoop_Ubuntu中使用终端运行Hadoop程序
  2. 如何快速开发一个支持高效、高并发的分布式ID生成器(二)
  3. tcp对连接断开的感知——保活定时器
  4. linux的进程/线程/协程系列3:查看linux内核源码——vim+ctags/find+grep
  5. opencv 叠加文字_opencv 图像上添加文字
  6. python特征选择后显示选取的特征名_python实现求特征选择的信息增益
  7. salesforce 架构设计_关于Salesforce证书维护重要通知
  8. JavaScript 基础(十三):Window对象
  9. HTML5第一弹:彩虹爆炸图
  10. 【汉化】DevExpress插件中RichEdit控件的自定义汉化方法