PacketClientConnecting

PacketClientConnecting

我有一个名为Packet的类,一个名为PacketClientConnecting的女巫对此进行了扩展。 PacketClientConnecting和其他数据包的实例存储在ArrayList<Packet>中。

我想以staticnon-static的方式访问ID值,例如PacketClientConnecting.getStaticId()packetArrayList.get(5).getId()

我该如何在不覆盖每个类的两个功能的情况下进行此操作?

最佳答案

我认为没有一种真正平滑的方法,但是可以通过使用反射(仅一次:在基类中)来实现您想要的:

class Packet {

    public static int getStaticId() {
        return 1;
    }

    // This method is virtual and will be inherited without change
    public int getId() {
        try {
            // Find and invoke the static method corresponding
            // to the run-time instance
            Method getStaticId = this.getClass().getMethod("getStaticId");
            return (Integer) getStaticId.invoke(null);

        // Catch three reflection-related exceptions at once, if you are on Java 7+,
        // use multi-catch or just ReflectiveOperationException
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }
}


现在,在子类中,您需要定义getStaticId():

class PacketClientConnecting extends Packet {
    public static int getStaticId() {
        return 2;
    }
}


让我们测试一下:

class Main {
    public static void main(String[] args) {
        // Both print 1
        System.out.println(Packet.getStaticId());
        System.out.println(new Packet().getId());

        // Both print 2
        System.out.println(PacketClientConnecting.getStaticId());
        System.out.println(new PacketClientConnecting().getId());
    }
}


如果要避免每次调用getId()时都要调用反射操作的开销,则可以使用基类中的字段来缓存ID:

class Packet {

    public static int getStaticId() {
        return 1;
    }

    private final int id = computeId();

    public int getId() {
        return id;
    }

    // This method runs once per instance created
    private int computeId() {
        try {
            Method getStaticId = this.getClass().getMethod("getStaticId");
            return (Integer) getStaticId.invoke(null);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }
}

09-16 11:52