Java方法重载混乱

Java方法重载混乱,java,inheritance,interface,overloading,Java,Inheritance,Interface,Overloading,在服务器代码中,我有一个ProtocolHandler类,它从套接字读取数据,找出它正在处理的数据包的类型,并将其发送给客户端。我尝试采用以下体系结构: public interface Packet { //... } public class ClientInformations implements Packet { //... } public class ProtocolHandler { //.... public void bytesReceiv

在服务器代码中,我有一个
ProtocolHandler
类,它从套接字读取数据,找出它正在处理的数据包的类型,并将其发送给客户端。我尝试采用以下体系结构:

public interface Packet {
    //...
}

public class ClientInformations implements Packet {
    //...
}

public class ProtocolHandler {
    //....
    public void bytesReceived(byte[] bytes) {
        //... Determine the type of the packet
        Packet packet = determineTypeOfPacketAndRead(bytes);

        // Here  I already have the packet object built,
        // like ClientInformations@1a1a1a1a[...]

        client.packetReceived(packet);
    }
    //...
}

public class Client {
    //...
    public void packetReceived(Packet pkt) { 
        System.out.println("Unimplemented packet received.");
    }

    public void packetReceived(ClientInformations ci) {

    }

    //...
}
(我不知道如何用语言轻松地解释它)。问题是,我真的以为会调用
packetReceived(ClientInformations)
,但事实并非如此。它调用更通用的
packetReceived(Packet)
方法。我错了吗?那么,我怎么还能使用相同的体系结构呢

--编辑


现在我明白了为什么会这样。问题是,我还有其他包类,比如
移动
同步
繁殖
。我想通过向
客户机
类添加一个新方法来简化添加新数据包的过程。那就没有别的办法了吗?我的意思是,一种在运行时自动分析
数据包
对象类型并执行最具体的方法调用的方法?

如果我理解正确,那么您传递的对象既是
数据包
又是
客户端信息
,因此,这两种方法都没有任何优先权


只要给另一个方法起一个不同的名字,你的问题就会解决。

如果我理解正确的话,你传递的对象既是
数据包
又是
客户端信息
,因此这两种方法都没有任何优先权


只需给另一种方法起一个不同的名字,您的问题就会得到解决。

您必须按照以下步骤进行操作:

public void bytesReceived(byte[] bytes) {
    //... Determine the type of the packet
    packet = determineTypeOfPacketAndRead(bytes);

    // Here  I already have the packet object built,
    // like ClientInformations@1a1a1a1a[...]

    if (packet instanceof ClientInformations) {
        ClientInformations ci = (ClientInformations)packet;
        client.packetReceived(ci); // this way, it's clear which method you want to call
    }
}

但是,我更喜欢Tim B的建议,即更改方法名称。我建议
clientinformationpacketreceived()

您必须按以下步骤执行:

public void bytesReceived(byte[] bytes) {
    //... Determine the type of the packet
    packet = determineTypeOfPacketAndRead(bytes);

    // Here  I already have the packet object built,
    // like ClientInformations@1a1a1a1a[...]

    if (packet instanceof ClientInformations) {
        ClientInformations ci = (ClientInformations)packet;
        client.packetReceived(ci); // this way, it's clear which method you want to call
    }
}

但是,我更喜欢Tim B的建议,即更改方法名称。我建议
clientinformationpacketreceived()

我假设您有
Packet-Packet=determineTYpeOfPacketAndRead(bytes)
,因为代码几乎没有其他编译方式

因此,即使对象类型是
ClientInformations
(在运行时),引用类型也是
Packet
(在编译时)

如Java语言规范第15章中所述,方法重载

在编译时选择最具体的方法;它的描述符确定在运行时实际执行的方法

更新:您的代码目前运行正常,因为您的代码中没有歧义,即使它的行为方式与您所希望的不同。但是,您将无法扩展此代码,因为它将导致问题,让我举例说明:

我先前的建议如下:

public class Client {
    //...
    public void unknownPacketReceived(Packet pkt) { 
        System.out.println("Unimplemented packet received.");
    }

    public void packetReceived(ClientInformations ci) {

    }

    //...
}
但是,这不能用作
ClientInformations
对象。作为一个简单的
数据包
对象/接口,它会产生以下编译错误:

incompatible types: Packet cannot be converted to ClientInformations
这是因为引用类型仍然只是
数据包
,而您希望将其提升为
客户端信息

但是,如果您将其称为:

client.receivedPacket((ClientInformations)packet)
在您的情况下,这不会造成任何伤害,因为在运行时,它们是相同类型的,因此在转换过程中不会丢失任何东西,这需要伴随一个
instanceof
树,这就是为什么现在回到步骤0的原因


这个程序不仅可以运行,如果你想让它变得简单,我建议你改变你的设计。如果你正在处理一个遗留的应用程序,继续这个路径可能是一个选择,而且不能仅仅改变一些东西,但这并不容易。

我假设你有
数据包=determineTYpeOfPacketAndRead(字节)
,因为几乎没有其他方法可以编译代码

因此,即使对象类型是
ClientInformations
(在运行时),引用类型也是
Packet
(在编译时)

如Java语言规范第15章中所述,方法重载

在编译时选择最具体的方法;它的描述符确定在运行时实际执行的方法

更新:您的代码目前运行正常,因为您的代码中没有歧义,即使它的行为方式与您所希望的不同。但是,您将无法扩展此代码,因为它将导致问题,让我举例说明:

我先前的建议如下:

public class Client {
    //...
    public void unknownPacketReceived(Packet pkt) { 
        System.out.println("Unimplemented packet received.");
    }

    public void packetReceived(ClientInformations ci) {

    }

    //...
}
但是,这不能用作
ClientInformations
对象。作为一个简单的
数据包
对象/接口,它会产生以下编译错误:

incompatible types: Packet cannot be converted to ClientInformations
这是因为引用类型仍然只是
数据包
,而您希望将其提升为
客户端信息

但是,如果您将其称为:

client.receivedPacket((ClientInformations)packet)
在您的情况下,这不会造成任何伤害,因为在运行时,它们是相同类型的,因此在转换过程中不会丢失任何东西,这需要伴随一个
instanceof
树,这就是为什么现在回到步骤0的原因


这个程序不仅可以运行,如果你想让它变得简单,我建议你改变你的设计。如果你正在处理一个遗留的应用程序,继续这个路径可能是一个选择,而且不能仅仅改变一些东西,但这并不容易。

你可以
类型转换
你的对象引用来调用
packetReceived(ClientInformations)
而不是
packetReceived(packetReceived)(packetReceived)(数据包)


您可以像这样调用client.packetReceived((ClientInformations)packet)

您可以
typecast
您的对象引用调用
packetReceived(ClientInformations)
而不是
packetReceived(Packet)


您可以像这样调用client.packetReceived((ClientInformations)packet)

Java是一种单一的调度语言,所以诀窍在于学会利用