旧问题,但没有答案提供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. linux php进程端口占用,linux如何查看端口占用情况
  2. iRank: 基于互联网类脑架构的阿尔法鹰眼发展趋势评估
  3. Python运维开发基础01-语法基础【转】
  4. linux php oauth安装,Linux php 扩展安装 mongo ,redis ,soap,imap,pdo_mysql,oauth
  5. java 不能继承的类_java中不能继承的类有哪些?
  6. DirectAdmin面板在线解压缩的.tar.gz文件
  7. java jsonproperty_将多个JSON字段映射到单个Java字段
  8. 微信小程序01-底部导航栏设置
  9. c语言数字语音播报,金额数字语音播报
  10. 菲尼克斯电源模块QUINT-PS3AC24DC40的组装说明
  11. oracle根据身份证号码 计算年龄、性别
  12. KNN算法说明以及sklearn 中 neighbors.KNeighborsClassifier参数说明
  13. win7 从网络访问此计算机',在里面把guest用户组添加上,大白菜修复win7系统没有权限访问网络资源的办法...
  14. Compression-Expansion Coding Improvements in MLC/TLC NVM论文解读
  15. Gulp老矣 尚能饭否
  16. endnote文件enl突然没了_科学网—实际操作中的Endnote库文件损坏修复方法 - 尹卓忻的博文...
  17. 携职教育:2022年初级会计考试证书领取流程及所需材料
  18. 【计算机组成原理】=【考研复试面试题】- 整合全家桶
  19. 周计划周记录:2022年6月6日-2022年6月12日
  20. 17.2 字体的背景知识

热门文章

  1. 【英语学习】【Daily English】U03 Leisure Time L02 I'm more of an indoorsy person anyway
  2. Intel 64/x86_64/IA-32/x86处理器 - 指令格式(2) - 8086/16位指令格式概述
  3. Mosquito的优化——其他优化(九)
  4. jmap简单实用示例
  5. python3 mysql库_Python3.7 MySQL 数据库连接
  6. python中、print程序设计基础输出是_在python编程里, print 4> 2 and 1 and 4 输出的是什么?...
  7. 算法笔记_096:蓝桥杯练习 算法提高 求最大值(Java)
  8. 在Ubuntu X64上编译Hadoop
  9. [六字真言]1.唵.遁入佛门之异常.md
  10. 图(网)的存储结构(数组存储表示即邻接矩阵、邻接表)